Imported Upstream version 3.0

This commit is contained in:
Sebastian Ramacher 2016-03-07 00:15:29 +01:00
parent 788abe4bd5
commit cc62001e2f
1590 changed files with 88869 additions and 33376 deletions

26
.travis.yml Normal file
View File

@ -0,0 +1,26 @@
language: c
sudo: false
os:
- linux
- osx
addons:
apt:
packages:
- yasm
- diffutils
compiler:
- clang
- gcc
cache:
directories:
- ffmpeg-samples
before_install:
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update --all; fi
install:
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install yasm; fi
script:
- mkdir -p ffmpeg-samples
- ./configure --samples=ffmpeg-samples --cc=$CC
- make -j 8
- make fate-rsync
- make check -j 8

347
Changelog
View File

@ -1,286 +1,75 @@
Entries are sorted chronologically from oldest to youngest within each release,
releases are sorted from youngest to oldest.
version 3.0:
- Common Encryption (CENC) MP4 encoding and decoding support
- DXV decoding
- extrastereo filter
- ocr filter
- alimiter filter
- stereowiden filter
- stereotools filter
- rubberband filter
- tremolo filter
- agate filter
- chromakey filter
- maskedmerge filter
- Screenpresso SPV1 decoding
- chromaprint fingerprinting muxer
- ffplay dynamic volume control
- displace filter
- selectivecolor filter
- extensive native AAC encoder improvements and removal of experimental flag
- ADPCM PSX decoder
- 3dostr, dcstr, fsb, genh, vag, xvag, ads, msf, svag & vpk demuxer
- zscale filter
- wve demuxer
- zero-copy Intel QSV transcoding in ffmpeg
- shuffleframes filter
- SDX2 DPCM decoder
- vibrato filter
- innoHeim/Rsupport Screen Capture Codec decoder
- ADPCM AICA decoder
- Interplay ACM demuxer and audio decoder
- XMA1 & XMA2 decoder
- realtime filter
- anoisesrc audio filter source
- IVR demuxer
- compensationdelay filter
- acompressor filter
- support encoding 16-bit RLE SGI images
- apulsator filter
- sidechaingate audio filter
- mipsdspr1 option has been renamed to mipsdsp
- aemphasis filter
- mips32r5 option has been removed
- mips64r6 option has been removed
- DXVA2-accelerated VP9 decoding
- SOFAlizer: virtual binaural acoustics filter
- VAAPI VP9 hwaccel
- audio high-order multiband parametric equalizer
- automatic bitstream filtering
- showspectrumpic filter
- libstagefright support removed
- spectrumsynth filter
- ahistogram filter
- only seek with the right mouse button in ffplay
- toggle full screen when double-clicking with the left mouse button in ffplay
- afftfilt filter
- convolution filter
- libquvi support removed
- support for dvaudio in wav and avi
- libaacplus and libvo-aacenc support removed
- Cineform HD decoder
- new DCA decoder with full support for DTS-HD extensions
- significant performance improvements in Windows Television (WTV) demuxer
- nnedi deinterlacer
- streamselect video and astreamselect audio filter
- swaprect filter
- metadata video and ametadata audio filter
- SMPTE VC-2 HQ profile support for the Dirac decoder
- SMPTE VC-2 native encoder supporting the HQ profile
version 2.8.6
- avcodec/jpeg2000dec: More completely check cdef
- avutil/opt: check for and handle errors in av_opt_set_dict2()
- avcodec/flacenc: fix calculation of bits required in case of custom sample rate
- avformat: Document urls a bit
- avformat/libquvi: Set default demuxer and protocol limitations
- avformat/concat: Check protocol prefix
- doc/demuxers: Document enable_drefs and use_absolute_path
- avcodec/mjpegdec: Check for end for both bytes in unescaping
- avcodec/mpegvideo_enc: Check for integer overflow in ff_mpv_reallocate_putbitbuffer()
- avformat/avformat: Replace some references to filenames by urls
- avcodec/wmaenc: Check ff_wma_init() for failure
- avcodec/mpeg12enc: Move high resolution thread check to before initializing threads
- avformat/img2dec: Use AVOpenCallback
- avformat/avio: Limit url option parsing to the documented cases
- avformat/img2dec: do not interpret the filename by default if a IO context has been opened
- avcodec/ass_split: Fix null pointer dereference in ff_ass_style_get()
- mov: Add an option to toggle dref opening
- avcodec/gif: Fix lzw buffer size
- avcodec/put_bits: Assert buf_ptr in flush_put_bits()
- avcodec/tiff: Check subsample & rps values more completely
- swscale/swscale: Add some sanity checks for srcSlice* parameters
- swscale/x86/rgb2rgb_template: Fix planar2x() for short width
- swscale/swscale_unscaled: Fix odd height inputs for bayer_to_yv12_wrapper()
- swscale/swscale_unscaled: Fix odd height inputs for bayer_to_rgb24_wrapper()
- avcodec/aacenc: Check both channels for finiteness
- asfdec_o: check for too small size in asf_read_unknown
- asfdec_o: break if EOF is reached after asf_read_packet_header
- asfdec_o: make sure packet_size is non-zero before seeking
- asfdec_o: prevent overflow causing seekback
- asfdec_o: check avio_skip in asf_read_simple_index
- asfdec_o: reject size > INT64_MAX in asf_read_unknown
- asfdec_o: only set asf_pkt->data_size after sanity checks
- Merge commit '8375dc1dd101d51baa430f34c0bcadfa37873896'
- dca: fix misaligned access in avpriv_dca_convert_bitstream
- brstm: fix missing closing brace
- brstm: also allocate b->table in read_packet
- brstm: make sure an ADPC chunk was read for adpcm_thp
- vorbisdec: reject rangebits 0 with non-0 partitions
- vorbisdec: reject channel mapping with less than two channels
- ffmdec: reset packet_end in case of failure
- avformat/ipmovie: put video decoding_map_size into packet and use it in decoder
- avformat/brstm: fix overflow
version 2.8.5
- avformat/hls: Even stricter URL checks
- avformat/hls: More strict url checks
- avcodec/pngenc: Fix mixed up linesizes
- avcodec/pngenc: Replace memcpy by av_image_copy()
- swscale/vscale: Check that 2 tap filters are bilinear before using bilinear code
- swscale: Move VScalerContext into vscale.c
- swscale/utils: Detect and skip unneeded sws_setColorspaceDetails() calls
- swscale/yuv2rgb: Increase YUV2RGB table headroom
- swscale/yuv2rgb: Factor YUVRGB_TABLE_LUMA_HEADROOM out
- avformat/hls: forbid all protocols except http(s) & file
- avformat/aviobuf: Fix end check in put_str16()
- avformat/asfenc: Check pts
- avcodec/mpeg4video: Check time_incr
- avcodec/wavpackenc: Check the number of channels
- avcodec/wavpackenc: Headers are per channel
- avcodec/aacdec_template: Check id_map
- avcodec/dvdec: Fix "left shift of negative value -254"
- avcodec/g2meet: Check for ff_els_decode_bit() failure in epic_decode_run_length()
- avcodec/mjpegdec: Fix negative shift
- avcodec/mss2: Check for repeat overflow
- avformat: Add integer fps from 31 to 60 to get_std_framerate()
- avformat/ivfenc: fix division by zero
- avcodec/mpegvideo_enc: Clip bits_per_raw_sample within valid range
- avfilter/vf_scale: set proper out frame color range
- avcodec/motion_est: Fix mv_penalty table size
- avcodec/h264_slice: Fix integer overflow in implicit weight computation
- swscale/utils: Use normal bilinear scaler if fast cannot be used due to tiny dimensions
- avcodec/put_bits: Always check buffer end before writing
- mjpegdec: extend check for incompatible values of s->rgb and s->ls
- swscale/utils: Fix intermediate format for cascaded alpha downscaling
- avformat/mov: Update handbrake_version threshold for full mp3 parsing
- x86/float_dsp: zero extend offset from ff_scalarproduct_float_sse
- avfilter/vf_zoompan: do not free frame we pushed to lavfi
- nuv: sanitize negative fps rate
- nutdec: reject negative value_len in read_sm_data
- xwddec: prevent overflow of lsize * avctx->height
- nutdec: only copy the header if it exists
- exr: fix out of bounds read in get_code
- on2avc: limit number of bits to 30 in get_egolomb
version 2.8.4
- rawdec: only exempt BIT0 with need_copy from buffer sanity check
- mlvdec: check that index_entries exist
- avcodec/mpeg4videodec: also for empty partitioned slices
- avcodec/h264_refs: Fix long_idx check
- avcodec/h264_mc_template: prefetch list1 only if it is used in the MB
- avcodec/h264_slice: Simplify ref2frm indexing
- avfilter/vf_mpdecimate: Add missing emms_c()
- sonic: make sure num_taps * channels is not larger than frame_size
- opus_silk: fix typo causing overflow in silk_stabilize_lsf
- ffm: reject invalid codec_id and codec_type
- golomb: always check for invalid UE golomb codes in get_ue_golomb
- sbr_qmf_analysis: sanitize input for 32-bit imdct
- sbrdsp_fixed: assert that input values are in the valid range
- aacsbr: ensure strictly monotone time borders
- aacenc: update max_sfb when num_swb changes
- aaccoder: prevent crash of anmr coder
- ffmdec: reject zero-sized chunks
- swscale/x86/rgb2rgb_template: Fallback to mmx in interleaveBytes() if the alignment is insufficient for SSE*
- swscale/x86/rgb2rgb_template: Do not crash on misaligend stride
- avformat/mxfenc: Do not crash if there is no packet in the first stream
- lavf/tee: fix side data double free.
- avformat/hlsenc: Check the return code of avformat_write_header()
- avformat/mov: Enable parser for mp3s by old HandBrake
- avformat/mxfenc: Fix integer overflow in length computation
- avformat/utils: estimate_timings_from_pts - increase retry counter, fixes invalid duration for ts files with hevc codec
- avformat/matroskaenc: Check codecdelay before use
- avutil/mathematics: Fix division by 0
- mjpegdec: consider chroma subsampling in size check
- libvpxenc: remove some unused ctrl id mappings
- avcodec/vp3: ensure header is parsed successfully before tables
- avcodec/jpeg2000dec: Check bpno in decode_cblk()
- avcodec/pgssubdec: Fix left shift of 255 by 24 places cannot be represented in type int
- swscale/utils: Fix for runtime error: left shift of negative value -1
- avcodec/hevc: Fix integer overflow of entry_point_offset
- avcodec/dirac_parser: Check that there is a previous PU before accessing it
- avcodec/dirac_parser: Add basic validity checks for next_pu_offset and prev_pu_offset
- avcodec/dirac_parser: Fix potential overflows in pointer checks
- avcodec/wmaprodec: Check bits per sample to be within the range not causing integer overflows
- avcodec/wmaprodec: Fix overflow of cutoff
- avformat/smacker: fix integer overflow with pts_inc
- avcodec/vp3: Fix "runtime error: left shift of negative value"
- avformat/riffdec: Initialize bitrate
- mpegencts: Fix overflow in cbr mode period calculations
- avutil/timecode: Fix fps check
- avutil/mathematics: return INT64_MIN (=AV_NOPTS_VALUE) from av_rescale_rnd() for overflows
- avcodec/apedec: Check length in long_filter_high_3800()
- avcodec/vp3: always set pix_fmt in theora_decode_header()
- avcodec/mpeg4videodec: Check available data before reading custom matrix
- avutil/mathematics: Do not treat INT64_MIN as positive in av_rescale_rnd
- avutil/integer: Fix av_mod_i() with negative dividend
- avformat/dump: Fix integer overflow in av_dump_format()
- avcodec/h264_refs: Check that long references match before use
- avcodec/utils: Clear dimensions in ff_get_buffer() on failure
- avcodec/utils: Use 64bit for aspect ratio calculation in avcodec_string()
- avcodec/hevc: Check max ctb addresses for WPP
- avcodec/vp3: Clear context on reinitialization failure
- avcodec/hevc: allocate entries unconditionally
- avcodec/hevc_cabac: Fix multiple integer overflows
- avcodec/jpeg2000dwt: Check ndeclevels before calling dwt_encode*()
- avcodec/jpeg2000dwt: Check ndeclevels before calling dwt_decode*()
- avcodec/hevc: Check entry_point_offsets
- lavf/rtpenc_jpeg: Less strict check for standard Huffman tables.
- avcodec/ffv1dec: Clear quant_table_count if its invalid
- avcodec/ffv1dec: Print an error if the quant table count is invalid
- doc/filters/drawtext: fix centering example
version 2.8.3
- avcodec/cabac: Check initial cabac decoder state
- avcodec/cabac_functions: Fix "left shift of negative value -31767"
- avcodec/h264_slice: Limit max_contexts when slice_context_count is initialized
- rtmpcrypt: Do the xtea decryption in little endian mode
- avformat/matroskadec: Check subtitle stream before dereferencing
- avcodec/pngdec: Replace assert by request for sample for unsupported TRNS cases
- avformat/utils: Do not init parser if probing is unfinished
- avcodec/jpeg2000dec: Fix potential integer overflow with tile dimensions
- avcodec/jpeg2000: Use av_image_check_size() in ff_jpeg2000_init_component()
- avcodec/wmaprodec: Check for overread in decode_packet()
- avcodec/smacker: Check that the data size is a multiple of a sample vector
- avcodec/takdec: Skip last p2 sample (which is unused)
- avcodec/dxtory: Fix input size check in dxtory_decode_v1_410()
- avcodec/dxtory: Fix input size check in dxtory_decode_v1_420()
- avcodec/error_resilience: avoid accessing previous or next frames tables beyond height
- avcodec/dpx: Move need_align to act per line
- avcodec/flashsv: Check size before updating it
- avcodec/ivi: Check image dimensions
- avcodec/utils: Better check for channels in av_get_audio_frame_duration()
- avcodec/jpeg2000dec: Check for duplicate SIZ marker
- aacsbr: don't call sbr_dequant twice without intermediate read_sbr_data
- hqx: correct type and size check of info_offset
- mxfdec: check edit_rate also for physical_track
- avcodec/jpeg2000: Change coord to 32bit to support larger than 32k width or height
- avcodec/jpeg2000dec: Check SIZ dimensions to be within the supported range
- avcodec/jpeg2000: Check comp coords to be within the supported size
- mpegvideo: clear overread in clear_context
- avcodec/avrndec: Use the AVFrame format instead of the context
- dds: disable palette flag for compressed images
- dds: validate compressed source buffer size
- dds: validate source buffer size before copying
- dvdsubdec: validate offset2 similar to offset1
- brstm: reject negative sample rate
- aacps: avoid division by zero in stereo_processing
- softfloat: assert when the argument of av_sqrt_sf is negative
version 2.8.2
- various fixes in the aac_fixed decoder
- various fixes in softfloat
- swresample/resample: increase precision for compensation
- lavf/mov: add support for sidx fragment indexes
- avformat/mxfenc: Only store user comment related tags when needed
- tests/fate/avformat: Fix fate-lavf
- doc/ffmpeg: Clarify that the sdp_file option requires an rtp output.
- ffmpeg: Don't try and write sdp info if none of the outputs had an rtp format.
- apng: use correct size for output buffer
- jvdec: avoid unsigned overflow in comparison
- avcodec/jpeg2000dec: Clip all tile coordinates
- avcodec/microdvddec: Check for string end in 'P' case
- avcodec/dirac_parser: Fix undefined memcpy() use
- avformat/xmv: Discard remainder of packet on error
- avformat/xmv: factor return check out of if/else
- avcodec/mpeg12dec: Do not call show_bits() with invalid bits
- avcodec/faxcompr: Add missing runs check in decode_uncompressed()
- libavutil/channel_layout: Check strtol*() for failure
- avformat/mpegts: Only start probing data streams within probe_packets
- avcodec/hevc_ps: Check chroma_format_idc
- avcodec/ffv1dec: Check for 0 quant tables
- avcodec/mjpegdec: Reinitialize IDCT on BPP changes
- avcodec/mjpegdec: Check index in ljpeg_decode_yuv_scan() before using it
- avutil/file_open: avoid file handle inheritance on Windows
- avcodec/h264_slice: Disable slice threads if there are multiple access units in a packet
- avformat/hls: update cookies on setcookie response
- opusdec: Don't run vector_fmul_scalar on zero length arrays
- avcodec/opusdec: Fix extra samples read index
- avcodec/ffv1: Initialize vlc_state on allocation
- avcodec/ffv1dec: update progress in case of broken pointer chains
- avcodec/ffv1dec: Clear slice coordinates if they are invalid or slice header decoding fails for other reasons
- rtsp: Allow $ as interleaved packet indicator before a complete response header
- videodsp: don't overread edges in vfix3 emu_edge.
- avformat/mp3dec: improve junk skipping heuristic
- concatdec: fix file_start_time calculation regression
- avcodec: loongson optimize h264dsp idct and loop filter with mmi
- avcodec/jpeg2000dec: Clear properties in jpeg2000_dec_cleanup() too
- avformat/hls: add support for EXT-X-MAP
- avformat/hls: fix segment selection regression on track changes of live streams
- configure: Require libkvazaar < 0.7.
- avcodec/vp8: Do not use num_coeff_partitions in thread/buffer setup
version 2.8.1:
- swscale: fix ticket #4881
- doc: fix spelling errors
- hls: only seek if there is an offset
- asfdec: add more checks for size left in asf packet buffer
- asfdec: alloc enough space for storing name in asf_read_metadata_obj
- avcodec/pngdec: Check blend_op.
- h264_mp4toannexb: fix pps offfset fault when there are more than one sps in avcc
- avcodec/h264_mp4toannexb_bsf: Use av_freep() to free spspps_buf
- avformat/avidec: Workaround broken initial frame
- avformat/hls: fix some cases of HLS streams which require cookies
- avcodec/pngdec: reset has_trns after every decode_frame_png()
- lavf/img2dec: Fix memory leak
- avcodec/mp3: fix skipping zeros
- avformat/srtdec: make sure we probe a number
- configure: check for ID3D11VideoContext
- avformat/vobsub: compare correct packet stream IDs
- avformat/srtdec: more lenient first line probing
- avformat/srtdec: fix number check for the first character
- avcodec/mips: build fix for MSA 64bit
- avcodec/mips: build fix for MSA
- avformat/httpauth: Add space after commas in HTTP/RTSP auth header
- libavformat/hlsenc: Use of uninitialized memory unlinking old files
- avcodec/x86/sbrdsp: Fix using uninitialized upper 32bit of noise
- avcodec/ffv1dec: Fix off by 1 error in quant_table_count check
- avcodec/ffv1dec: Explicitly check read_quant_table() return value
- dnxhddata: correct weight tables
- dnxhddec: decode and use interlace mb flag
- swscale: fix ticket #4877
- avcodec/rangecoder: Check e
- avcodec/ffv1: separate slice_count from max_slice_count
- swscale: fix ticket 4850
- cmdutils: Filter dst/srcw/h
- avutil/log: fix zero length gnu_printf format string warning
- lavf/webvttenc: Require webvtt file to contain exactly one WebVTT stream.
- swscale/swscale: Fix "unused variable" warning
- avcodec/mjpegdec: Fix decoding RGBA RCT LJPEG
- MAINTAINERS: add 2.8, drop 2.2
- doc: mention libavcodec can decode Opus natively
- hevc: properly handle no_rasl_output_flag when removing pictures from the DPB
- avfilter/af_ladspa: process all channels for nb_handles > 1
- configure: add libsoxr to swresample's pkgconfig
- lavc: Fix compilation with --disable-everything --enable-parser=mpeg4video.
version 2.8:
- colorkey video filter

View File

@ -85,6 +85,7 @@ compatible libraries
The following libraries are under GPL:
- frei0r
- libcdio
- librubberband
- libutvideo
- libvidstab
- libx264
@ -103,7 +104,7 @@ license version needs to be upgraded by passing `--enable-version3` to configure
incompatible libraries
----------------------
The Fraunhofer AAC library, FAAC and aacplus are under licenses which
The Fraunhofer AAC library and FAAC 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.

View File

@ -71,6 +71,7 @@ Internal Interfaces:
libavutil/common.h Michael Niedermayer
Other:
aes_ctr.c, aes_ctr.h Eran Kornblau
bprint Nicolas George
bswap.h
des Reimar Doeffinger
@ -164,6 +165,7 @@ Codecs:
crystalhd.c Philip Langdale
cscd.c Reimar Doeffinger
dca.c Kostya Shishkov, Benjamin Larsson
dirac* Rostislav Pehlivanov
dnxhd* Baptiste Coudurier
dpcm.c Mike Melanson
dss_sp.c Oleksij Rempel, Michael Niedermayer
@ -185,6 +187,7 @@ Codecs:
h261* Michael Niedermayer
h263* Michael Niedermayer
h264* Loren Merritt, Michael Niedermayer
hap* Tom Butterworth
huffyuv* Michael Niedermayer, Christophe Gisquet
idcinvideo.c Mike Melanson
imc* Benjamin Larsson
@ -207,7 +210,7 @@ Codecs:
libschroedinger* David Conrad
libspeexdec.c Justin Ruggles
libtheoraenc.c David Conrad
libutvideo* Derek Buitenhuis
libutvideo* Carl Eugen Hoyos
libvorbis.c David Conrad
libvpx* James Zern
libx264.c Mans Rullgard, Jason Garrett-Glaser
@ -273,6 +276,7 @@ Codecs:
vb.c Kostya Shishkov
vble.c Derek Buitenhuis
vc1* Kostya Shishkov, Christophe Gisquet
vc2* Rostislav Pehlivanov
vcr1.c Michael Niedermayer
vda_h264_dec.c Xidorn Quan
vima.c Paul B Mahol
@ -302,7 +306,6 @@ Codecs:
Hardware acceleration:
crystalhd.c Philip Langdale
dxva2* Hendrik Leppkes, Laurent Aimar
libstagefright.cpp Mohamed Naufal
vaapi* Gwenole Beauchesne
vda* Sebastien Zwickert
vdpau* Philip Langdale, Carl Eugen Hoyos
@ -346,7 +349,6 @@ Filters:
af_aphaser.c Paul B Mahol
af_aresample.c Michael Niedermayer
af_astats.c Paul B Mahol
af_astreamsync.c Nicolas George
af_atempo.c Pavel Koshevoy
af_biquads.c Paul B Mahol
af_chorus.c Paul B Mahol
@ -359,13 +361,14 @@ Filters:
avf_avectorscope.c Paul B Mahol
avf_showcqt.c Muhammad Faiz
vf_blend.c Paul B Mahol
vf_chromakey.c Timo Rothenpieler
vf_colorchannelmixer.c Paul B Mahol
vf_colorbalance.c Paul B Mahol
vf_colorkey.c Timo Rothenpieler
vf_colorlevels.c Paul B Mahol
vf_deband.c Paul B Mahol
vf_dejudder.c Nicholas Robbins
vf_delogo.c Jean Delvare (CC <khali@linux-fr.org>)
vf_delogo.c Jean Delvare (CC <jdelvare@suse.com>)
vf_drawbox.c/drawgrid Andrey Utkin
vf_extractplanes.c Paul B Mahol
vf_histogram.c Paul B Mahol
@ -457,6 +460,7 @@ Muxers/Demuxers:
mm.c Peter Ross
mov.c Michael Niedermayer, Baptiste Coudurier
movenc.c Baptiste Coudurier, Matthieu Bouron
movenccenc.c Eran Kornblau
mpc.c Kostya Shishkov
mpeg.c Michael Niedermayer
mpegenc.c Michael Niedermayer
@ -473,6 +477,7 @@ Muxers/Demuxers:
oggdec.c, oggdec.h David Conrad
oggenc.c Baptiste Coudurier
oggparse*.c David Conrad
oggparsedaala* Rostislav Pehlivanov
oma.c Maxim Poliakovski
paf.c Paul B Mahol
psxstr.c Mike Melanson
@ -588,6 +593,7 @@ Clément Bœsch 52D0 3A82 D445 F194 DB8B 2B16 87EE 2CB8 F4B8 FCF
Daniel Verkamp 78A6 07ED 782C 653E C628 B8B9 F0EB 8DD8 2F0E 21C7
Diego Biurrun 8227 1E31 B6D9 4994 7427 E220 9CAE D6CC 4757 FCC5
FFmpeg release signing key FCF9 86EA 15E6 E293 A564 4F10 B432 2F04 D676 58D8
Ganesh Ajjanagadde C96A 848E 97C3 CEA2 AB72 5CE4 45F9 6A2D 3C36 FB1B
Gwenole Beauchesne 2E63 B3A6 3E44 37E2 017D 2704 53C7 6266 B153 99C4
Jaikrishnan Menon 61A1 F09F 01C9 2D45 78E1 C862 25DC 8831 AF70 D368
Jean Delvare 7CA6 9F44 60F1 BDC4 1FD2 C858 A552 6B9B B3CD 4E6A

View File

@ -4,6 +4,7 @@ include config.mak
vpath %.c $(SRC_PATH)
vpath %.cpp $(SRC_PATH)
vpath %.h $(SRC_PATH)
vpath %.inc $(SRC_PATH)
vpath %.m $(SRC_PATH)
vpath %.S $(SRC_PATH)
vpath %.asm $(SRC_PATH)
@ -35,6 +36,7 @@ ifndef CONFIG_VIDEOTOOLBOX
OBJS-ffmpeg-$(CONFIG_VDA) += ffmpeg_videotoolbox.o
endif
OBJS-ffmpeg-$(CONFIG_VIDEOTOOLBOX) += ffmpeg_videotoolbox.o
OBJS-ffmpeg-$(CONFIG_LIBMFX) += ffmpeg_qsv.o
OBJS-ffserver += ffserver_config.o
TESTTOOLS = audiogen videogen rotozoom tiny_psnr tiny_ssim base64
@ -84,7 +86,7 @@ SUBDIR_VARS := CLEANFILES EXAMPLES FFLIBS HOSTPROGS TESTPROGS TOOLS \
HEADERS ARCH_HEADERS BUILT_HEADERS SKIPHEADERS \
ARMV5TE-OBJS ARMV6-OBJS ARMV8-OBJS VFP-OBJS NEON-OBJS \
ALTIVEC-OBJS MMX-OBJS YASM-OBJS \
MIPSFPU-OBJS MIPSDSPR2-OBJS MIPSDSPR1-OBJS MSA-OBJS \
MIPSFPU-OBJS MIPSDSPR2-OBJS MIPSDSP-OBJS MSA-OBJS \
MMI-OBJS OBJS SLIBOBJS HOSTOBJS TESTOBJS
define RESET
@ -175,11 +177,15 @@ clean::
$(RM) $(CLEANSUFFIXES)
$(RM) $(CLEANSUFFIXES:%=tools/%)
$(RM) -r coverage-html
$(RM) -rf coverage.info lcov
$(RM) -rf coverage.info coverage.info.in lcov
distclean::
$(RM) $(DISTCLEANSUFFIXES)
$(RM) config.* .config libavutil/avconfig.h .version avversion.h version.h libavutil/ffversion.h libavcodec/codec_names.h
ifeq ($(SRC_LINK),src)
$(RM) src
endif
$(RM) -rf doc/examples/pc-uninstalled
config:
$(SRC_PATH)/configure $(value FFMPEG_CONFIGURATION)

View File

@ -16,12 +16,12 @@ such as audio, video, subtitles and related metadata.
## Tools
* [ffmpeg](http://ffmpeg.org/ffmpeg.html) is a command line toolbox to
* [ffmpeg](https://ffmpeg.org/ffmpeg.html) is a command line toolbox to
manipulate, convert and stream multimedia content.
* [ffplay](http://ffmpeg.org/ffplay.html) is a minimalistic multimedia player.
* [ffprobe](http://ffmpeg.org/ffprobe.html) is a simple analysis tool to inspect
* [ffplay](https://ffmpeg.org/ffplay.html) is a minimalistic multimedia player.
* [ffprobe](https://ffmpeg.org/ffprobe.html) is a simple analysis tool to inspect
multimedia content.
* [ffserver](http://ffmpeg.org/ffserver.html) is a multimedia streaming server
* [ffserver](https://ffmpeg.org/ffserver.html) is a multimedia streaming server
for live broadcasts.
* Additional small tools such as `aviocat`, `ismindex` and `qt-faststart`.
@ -29,8 +29,8 @@ such as audio, video, subtitles and related metadata.
The offline documentation is available in the **doc/** directory.
The online documentation is available in the main [website](http://ffmpeg.org)
and in the [wiki](http://trac.ffmpeg.org).
The online documentation is available in the main [website](https://ffmpeg.org)
and in the [wiki](https://trac.ffmpeg.org).
### Examples
@ -40,3 +40,10 @@ Coding examples are available in the **doc/examples** directory.
FFmpeg codebase is mainly LGPL-licensed with optional components licensed under
GPL. Please refer to the LICENSE file for detailed information.
## Contributing
Patches should be submitted to the ffmpeg-devel mailing list using
`git format-patch` or `git send-email`. Github pull requests should be
avoided because they are not part of our review process. Few developers
follow pull requests so they will likely be ignored.

View File

@ -1 +1 @@
2.8.6
3.0

View File

@ -1,10 +1,10 @@
┌────────────────────────────────────────┐
│ RELEASE NOTES for FFmpeg 2.8 "Feynman" │
└────────────────────────────────────────┘
┌────────────────────────────────────────
│ RELEASE NOTES for FFmpeg 3.0 "Einstein" │
└────────────────────────────────────────
The FFmpeg Project proudly presents FFmpeg 2.8 "Feynman", about 3
months after the release of FFmpeg 2.7.
The FFmpeg Project proudly presents FFmpeg 3.0 "Einstein", about 5
months after the release of FFmpeg 2.8.
A complete Changelog is available at the root of the project, and the
complete Git history on http://source.ffmpeg.org.

View File

@ -1 +1 @@
2.8.6
3.0

View File

@ -5,7 +5,7 @@ OBJS-$(HAVE_VFP) += $(VFP-OBJS) $(VFP-OBJS-yes)
OBJS-$(HAVE_NEON) += $(NEON-OBJS) $(NEON-OBJS-yes)
OBJS-$(HAVE_MIPSFPU) += $(MIPSFPU-OBJS) $(MIPSFPU-OBJS-yes)
OBJS-$(HAVE_MIPSDSPR1) += $(MIPSDSPR1-OBJS) $(MIPSDSPR1-OBJS-yes)
OBJS-$(HAVE_MIPSDSP) += $(MIPSDSP-OBJS) $(MIPSDSP-OBJS-yes)
OBJS-$(HAVE_MIPSDSPR2) += $(MIPSDSPR2-OBJS) $(MIPSDSPR2-OBJS-yes)
OBJS-$(HAVE_MSA) += $(MSA-OBJS) $(MSA-OBJS-yes)
OBJS-$(HAVE_MMI) += $(MMI-OBJS) $(MMI-OBJS-yes)

View File

@ -52,6 +52,7 @@
#include "libavutil/opt.h"
#include "libavutil/cpu.h"
#include "libavutil/ffversion.h"
#include "libavutil/version.h"
#include "cmdutils.h"
#if CONFIG_NETWORK
#include "libavformat/network.h"
@ -533,7 +534,12 @@ int opt_default(void *optctx, const char *opt, const char *arg)
#if CONFIG_AVRESAMPLE
const AVClass *rc = avresample_get_class();
#endif
const AVClass *sc, *swr_class;
#if CONFIG_SWSCALE
const AVClass *sc = sws_get_class();
#endif
#if CONFIG_SWRESAMPLE
const AVClass *swr_class = swr_get_class();
#endif
if (!strcmp(opt, "debug") || !strcmp(opt, "fdebug"))
av_log_set_level(AV_LOG_DEBUG);
@ -557,7 +563,6 @@ int opt_default(void *optctx, const char *opt, const char *arg)
consumed = 1;
}
#if CONFIG_SWSCALE
sc = sws_get_class();
if (!consumed && (o = opt_find(&sc, opt, NULL, 0,
AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
struct SwsContext *sws = sws_alloc_context();
@ -585,7 +590,6 @@ int opt_default(void *optctx, const char *opt, const char *arg)
}
#endif
#if CONFIG_SWRESAMPLE
swr_class = swr_get_class();
if (!consumed && (o=opt_find(&swr_class, opt, NULL, 0,
AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ))) {
struct SwrContext *swr = swr_alloc();
@ -1055,7 +1059,8 @@ static int warned_cfg = 0;
LIB##LIBNAME##_VERSION_MAJOR, \
LIB##LIBNAME##_VERSION_MINOR, \
LIB##LIBNAME##_VERSION_MICRO, \
version >> 16, version >> 8 & 0xff, version & 0xff); \
AV_VERSION_MAJOR(version), AV_VERSION_MINOR(version),\
AV_VERSION_MICRO(version)); \
} \
if (flags & SHOW_CONFIG) { \
const char *cfg = libname##_configuration(); \
@ -1074,15 +1079,15 @@ static int warned_cfg = 0;
static void print_all_libs_info(int flags, int level)
{
PRINT_LIB_INFO(avutil, AVUTIL, flags, level);
PRINT_LIB_INFO(avcodec, AVCODEC, flags, level);
PRINT_LIB_INFO(avformat, AVFORMAT, flags, level);
PRINT_LIB_INFO(avdevice, AVDEVICE, flags, level);
PRINT_LIB_INFO(avfilter, AVFILTER, flags, level);
PRINT_LIB_INFO(avutil, AVUTIL, flags, level);
PRINT_LIB_INFO(avcodec, AVCODEC, flags, level);
PRINT_LIB_INFO(avformat, AVFORMAT, flags, level);
PRINT_LIB_INFO(avdevice, AVDEVICE, flags, 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);
PRINT_LIB_INFO(swscale, SWSCALE, flags, level);
PRINT_LIB_INFO(swresample, SWRESAMPLE, flags, level);
PRINT_LIB_INFO(postproc, POSTPROC, flags, level);
}
static void print_program_info(int flags, int level)
@ -1319,16 +1324,47 @@ static void print_codec(const AVCodec *c)
printf("%s %s [%s]:\n", encoder ? "Encoder" : "Decoder", c->name,
c->long_name ? c->long_name : "");
printf(" General capabilities: ");
if (c->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND)
printf("horizband ");
if (c->capabilities & AV_CODEC_CAP_DR1)
printf("dr1 ");
if (c->capabilities & AV_CODEC_CAP_TRUNCATED)
printf("trunc ");
if (c->capabilities & AV_CODEC_CAP_DELAY)
printf("delay ");
if (c->capabilities & AV_CODEC_CAP_SMALL_LAST_FRAME)
printf("small ");
if (c->capabilities & AV_CODEC_CAP_SUBFRAMES)
printf("subframes ");
if (c->capabilities & AV_CODEC_CAP_EXPERIMENTAL)
printf("exp ");
if (c->capabilities & AV_CODEC_CAP_CHANNEL_CONF)
printf("chconf ");
if (c->capabilities & AV_CODEC_CAP_PARAM_CHANGE)
printf("paramchange ");
if (c->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)
printf("variable ");
if (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS |
AV_CODEC_CAP_SLICE_THREADS |
AV_CODEC_CAP_AUTO_THREADS))
printf("threads ");
if (!c->capabilities)
printf("none");
printf("\n");
if (c->type == AVMEDIA_TYPE_VIDEO ||
c->type == AVMEDIA_TYPE_AUDIO) {
printf(" Threading capabilities: ");
switch (c->capabilities & (AV_CODEC_CAP_FRAME_THREADS |
AV_CODEC_CAP_SLICE_THREADS)) {
AV_CODEC_CAP_SLICE_THREADS |
AV_CODEC_CAP_AUTO_THREADS)) {
case AV_CODEC_CAP_FRAME_THREADS |
AV_CODEC_CAP_SLICE_THREADS: printf("frame and slice"); break;
case AV_CODEC_CAP_FRAME_THREADS: printf("frame"); break;
case AV_CODEC_CAP_SLICE_THREADS: printf("slice"); break;
default: printf("no"); break;
case AV_CODEC_CAP_AUTO_THREADS : printf("auto"); break;
default: printf("none"); break;
}
printf("\n");
}
@ -1387,7 +1423,7 @@ 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 :
return (*da)->type != (*db)->type ? FFDIFFSIGN((*da)->type, (*db)->type) :
strcmp((*da)->name, (*db)->name);
}
@ -1589,7 +1625,7 @@ int show_filters(void *optctx, const char *opt, const char *arg)
( i && (filter->flags & AVFILTER_FLAG_DYNAMIC_OUTPUTS))) ? 'N' : '|';
}
*descr_cur = 0;
printf(" %c%c%c %-16s %-10s %s\n",
printf(" %c%c%c %-17s %-10s %s\n",
filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE ? 'T' : '.',
filter->flags & AVFILTER_FLAG_SLICE_THREADS ? 'S' : '.',
filter->process_command ? 'C' : '.',

View File

@ -19,8 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FFMPEG_CMDUTILS_H
#define FFMPEG_CMDUTILS_H
#ifndef CMDUTILS_H
#define CMDUTILS_H
#include <stdint.h>

View File

@ -206,7 +206,9 @@ end:
static int compare_ocl_device_desc(const void *a, const void *b)
{
return ((OpenCLDeviceBenchmark*)a)->runtime - ((OpenCLDeviceBenchmark*)b)->runtime;
const OpenCLDeviceBenchmark* va = (const OpenCLDeviceBenchmark*)a;
const OpenCLDeviceBenchmark* vb = (const OpenCLDeviceBenchmark*)b;
return FFDIFFSIGN(va->runtime , vb->runtime);
}
int opt_opencl_bench(void *optctx, const char *opt, const char *arg)

View File

@ -18,7 +18,7 @@ ifndef SUBDIR
ifndef V
Q = @
ECHO = printf "$(1)\t%s\n" $(2)
BRIEF = CC CXX HOSTCC HOSTLD AS YASM AR LD STRIP CP WINDRES
BRIEF = CC CXX OBJCC HOSTCC HOSTLD AS YASM AR LD STRIP CP WINDRES
SILENT = DEPCC DEPHOSTCC DEPAS DEPYASM RANLIB RM
MSG = $@
@ -32,10 +32,12 @@ endif
ALLFFLIBS = avcodec avdevice avfilter avformat avresample avutil postproc swscale swresample
# NASM requires -I path terminated with /
IFLAGS := -I. -I$(SRC_PATH)/
IFLAGS := -I. -I$(SRC_LINK)/
CPPFLAGS := $(IFLAGS) $(CPPFLAGS)
CFLAGS += $(ECFLAGS)
CCFLAGS = $(CPPFLAGS) $(CFLAGS)
OBJCFLAGS += $(EOBJCFLAGS)
OBJCCFLAGS = $(CPPFLAGS) $(CFLAGS) $(OBJCFLAGS)
ASFLAGS := $(CPPFLAGS) $(ASFLAGS)
CXXFLAGS += $(CPPFLAGS) $(CFLAGS)
YASMFLAGS += $(IFLAGS:%=%/) -Pconfig.asm
@ -45,12 +47,13 @@ LDFLAGS := $(ALLFFLIBS:%=$(LD_PATH)lib%) $(LDFLAGS)
define COMPILE
$(call $(1)DEP,$(1))
$($(1)) $($(1)FLAGS) $($(1)_DEPFLAGS) $($(1)_C) $($(1)_O) $<
$($(1)) $($(1)FLAGS) $($(1)_DEPFLAGS) $($(1)_C) $($(1)_O) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<)
endef
COMPILE_C = $(call COMPILE,CC)
COMPILE_CXX = $(call COMPILE,CXX)
COMPILE_S = $(call COMPILE,AS)
COMPILE_M = $(call COMPILE,OBJCC)
COMPILE_HOSTC = $(call COMPILE,HOSTCC)
%.o: %.c
@ -60,10 +63,10 @@ COMPILE_HOSTC = $(call COMPILE,HOSTCC)
$(COMPILE_CXX)
%.o: %.m
$(COMPILE_C)
$(COMPILE_M)
%.s: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -S -o $@ $<
$(CC) $(CCFLAGS) -S -o $@ $<
%.o: %.S
$(COMPILE_S)
@ -81,7 +84,9 @@ COMPILE_HOSTC = $(call COMPILE,HOSTCC)
$(Q)echo '#include "$*.h"' >$@
%.ver: %.v
$(Q)sed 's/$$MAJOR/$($(basename $(@F))_VERSION_MAJOR)/' $^ > $@
$(Q)sed 's/$$MAJOR/$($(basename $(@F))_VERSION_MAJOR)/' $^ | sed -e 's/:/:\
/' -e 's/; /;\
/g' > $@
%.c %.h: TAG = GEN
@ -147,7 +152,7 @@ $(TOOLOBJS): | tools
OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SLIBOBJS) $(TESTOBJS))
CLEANSUFFIXES = *.d *.o *~ *.h.c *.map *.ver *.ho *.gcno *.gcda *$(DEFAULT_YASMD).asm
CLEANSUFFIXES = *.d *.o *~ *.h.c *.map *.ver *.ver-sol2 *.ho *.gcno *.gcda *$(DEFAULT_YASMD).asm
DISTCLEANSUFFIXES = *.pc
LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a

View File

@ -19,8 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FFMPEG_COMPAT_AIX_MATH_H
#define FFMPEG_COMPAT_AIX_MATH_H
#ifndef COMPAT_AIX_MATH_H
#define COMPAT_AIX_MATH_H
#define class class_in_math_h_causes_problems
@ -28,4 +28,4 @@
#undef class
#endif /* FFMPEG_COMPAT_AIX_MATH_H */
#endif /* COMPAT_AIX_MATH_H */

View File

@ -19,8 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef COMPAT_SNPRINTF_H
#define COMPAT_SNPRINTF_H
#ifndef COMPAT_MSVCRT_SNPRINTF_H
#define COMPAT_MSVCRT_SNPRINTF_H
#include <stdarg.h>
#include <stdio.h>
@ -35,4 +35,4 @@ int avpriv_vsnprintf(char *s, size_t n, const char *fmt, va_list ap);
#define _snprintf avpriv_snprintf
#define vsnprintf avpriv_vsnprintf
#endif /* COMPAT_SNPRINTF_H */
#endif /* COMPAT_MSVCRT_SNPRINTF_H */

View File

@ -23,8 +23,8 @@
* os2threads to pthreads wrapper
*/
#ifndef AVCODEC_OS2PTHREADS_H
#define AVCODEC_OS2PTHREADS_H
#ifndef COMPAT_OS2THREADS_H
#define COMPAT_OS2THREADS_H
#define INCL_DOS
#include <os2.h>
@ -32,59 +32,71 @@
#undef __STRICT_ANSI__ /* for _beginthread() */
#include <stdlib.h>
#include "libavutil/mem.h"
#include <sys/builtin.h>
#include <sys/fmutex.h>
#include "libavutil/attributes.h"
typedef struct {
TID tid;
void *(*start_routine)(void *);
void *arg;
void *result;
} pthread_t;
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;
HEV event_sem;
HEV ack_sem;
volatile unsigned wait_count;
} pthread_cond_t;
typedef void pthread_condattr_t;
struct thread_arg {
void *(*start_routine)(void *);
void *arg;
};
typedef struct {
volatile int done;
_fmutex mtx;
} pthread_once_t;
#define PTHREAD_ONCE_INIT {0, _FMUTEX_INITIALIZER}
static void thread_entry(void *arg)
{
struct thread_arg *thread_arg = arg;
pthread_t *thread = arg;
thread_arg->start_routine(thread_arg->arg);
av_free(thread_arg);
thread->result = thread->start_routine(thread->arg);
}
static av_always_inline int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *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->start_routine = start_routine;
thread->arg = arg;
thread->result = NULL;
thread_arg = av_mallocz(sizeof(struct thread_arg));
if (!thread_arg)
return ENOMEM;
thread_arg->start_routine = start_routine;
thread_arg->arg = arg;
*thread = _beginthread(thread_entry, NULL, 256 * 1024, thread_arg);
thread->tid = _beginthread(thread_entry, NULL, 1024 * 1024, thread);
return 0;
}
static av_always_inline int pthread_join(pthread_t thread, void **value_ptr)
{
DosWaitThread((PTID)&thread, DCWW_WAIT);
DosWaitThread(&thread.tid, DCWW_WAIT);
if (value_ptr)
*value_ptr = thread.result;
return 0;
}
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *attr)
{
DosCreateMutexSem(NULL, (PHMTX)mutex, 0, FALSE);
@ -112,9 +124,11 @@ static av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
return 0;
}
static av_always_inline int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
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);
DosCreateEventSem(NULL, &cond->ack_sem, DCE_POSTONE, FALSE);
cond->wait_count = 0;
@ -124,16 +138,16 @@ static av_always_inline int pthread_cond_init(pthread_cond_t *cond, const pthrea
static av_always_inline int pthread_cond_destroy(pthread_cond_t *cond)
{
DosCloseEventSem(cond->event_sem);
DosCloseEventSem(cond->ack_sem);
return 0;
}
static av_always_inline int pthread_cond_signal(pthread_cond_t *cond)
{
if (cond->wait_count > 0) {
if (!__atomic_cmpxchg32(&cond->wait_count, 0, 0)) {
DosPostEventSem(cond->event_sem);
cond->wait_count--;
DosWaitEventSem(cond->ack_sem, SEM_INDEFINITE_WAIT);
}
return 0;
@ -141,26 +155,47 @@ static av_always_inline int pthread_cond_signal(pthread_cond_t *cond)
static av_always_inline int pthread_cond_broadcast(pthread_cond_t *cond)
{
while (cond->wait_count > 0) {
DosPostEventSem(cond->event_sem);
cond->wait_count--;
}
while (!__atomic_cmpxchg32(&cond->wait_count, 0, 0))
pthread_cond_signal(cond);
return 0;
}
static av_always_inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
static av_always_inline int pthread_cond_wait(pthread_cond_t *cond,
pthread_mutex_t *mutex)
{
cond->wait_count++;
__atomic_increment(&cond->wait_count);
pthread_mutex_unlock(mutex);
DosWaitEventSem(cond->event_sem, SEM_INDEFINITE_WAIT);
__atomic_decrement(&cond->wait_count);
DosPostEventSem(cond->ack_sem);
pthread_mutex_lock(mutex);
return 0;
}
#endif /* AVCODEC_OS2PTHREADS_H */
static av_always_inline int pthread_once(pthread_once_t *once_control,
void (*init_routine)(void))
{
if (!once_control->done)
{
_fmutex_request(&once_control->mtx, 0);
if (!once_control->done)
{
init_routine();
once_control->done = 1;
}
_fmutex_release(&once_control->mtx);
}
return 0;
}
#endif /* COMPAT_OS2THREADS_H */

352
compat/solaris/make_sunver.pl Executable file
View File

@ -0,0 +1,352 @@
#!/usr/bin/env perl
# make_sunver.pl
#
# Copyright (C) 2010, 2011, 2012, 2013
# Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# 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; see the file COPYING.GPLv3. If not see
# <http://www.gnu.org/licenses/>.
# This script takes at least two arguments, a GNU style version script and
# a list of object and archive files, and generates a corresponding Sun
# style version script as follows:
#
# Each glob pattern, C++ mangled pattern or literal in the input script is
# matched against all global symbols in the input objects, emitting those
# that matched (or nothing if no match was found).
# A comment with the original pattern and its type is left in the output
# file to make it easy to understand the matches.
#
# It uses elfdump when present (native), GNU readelf otherwise.
# It depends on the GNU version of c++filt, since it must understand the
# GNU mangling style.
use FileHandle;
use IPC::Open2;
# Enforce C locale.
$ENV{'LC_ALL'} = "C";
$ENV{'LANG'} = "C";
# Input version script, GNU style.
my $symvers = shift;
##########
# Get all the symbols from the library, match them, and add them to a hash.
my %sym_hash = ();
# List of objects and archives to process.
my @OBJECTS = ();
# List of shared objects to omit from processing.
my @SHAREDOBJS = ();
# Filter out those input archives that have corresponding shared objects to
# avoid adding all symbols matched in the archive to the output map.
foreach $file (@ARGV) {
if (($so = $file) =~ s/\.a$/.so/ && -e $so) {
printf STDERR "omitted $file -> $so\n";
push (@SHAREDOBJS, $so);
} else {
push (@OBJECTS, $file);
}
}
# We need to detect and ignore hidden symbols. Solaris nm can only detect
# this in the harder to parse default output format, and GNU nm not at all,
# so use elfdump -s in the native case and GNU readelf -s otherwise.
# GNU objdump -t cannot be used since it produces a variable number of
# columns.
# The path to elfdump.
my $elfdump = "/usr/ccs/bin/elfdump";
if (-f $elfdump) {
open ELFDUMP,$elfdump.' -s '.(join ' ',@OBJECTS).'|' or die $!;
my $skip_arsym = 0;
while (<ELFDUMP>) {
chomp;
# Ignore empty lines.
if (/^$/) {
# End of archive symbol table, stop skipping.
$skip_arsym = 0 if $skip_arsym;
next;
}
# Keep skipping until end of archive symbol table.
next if ($skip_arsym);
# Ignore object name header for individual objects and archives.
next if (/:$/);
# Ignore table header lines.
next if (/^Symbol Table Section:/);
next if (/index.*value.*size/);
# Start of archive symbol table: start skipping.
if (/^Symbol Table: \(archive/) {
$skip_arsym = 1;
next;
}
# Split table.
(undef, undef, undef, undef, $bind, $oth, undef, $shndx, $name) = split;
# Error out for unknown input.
die "unknown input line:\n$_" unless defined($bind);
# Ignore local symbols.
next if ($bind eq "LOCL");
# Ignore hidden symbols.
next if ($oth eq "H");
# Ignore undefined symbols.
next if ($shndx eq "UNDEF");
# Error out for unhandled cases.
if ($bind !~ /^(GLOB|WEAK)/ or $oth ne "D") {
die "unhandled symbol:\n$_";
}
# Remember symbol.
$sym_hash{$name}++;
}
close ELFDUMP or die "$elfdump error";
} else {
open READELF, 'readelf -s -W '.(join ' ',@OBJECTS).'|' or die $!;
# Process each symbol.
while (<READELF>) {
chomp;
# Ignore empty lines.
next if (/^$/);
# Ignore object name header.
next if (/^File: .*$/);
# Ignore table header lines.
next if (/^Symbol table.*contains.*:/);
next if (/Num:.*Value.*Size/);
# Split table.
(undef, undef, undef, undef, $bind, $vis, $ndx, $name) = split;
# Error out for unknown input.
die "unknown input line:\n$_" unless defined($bind);
# Ignore local symbols.
next if ($bind eq "LOCAL");
# Ignore hidden symbols.
next if ($vis eq "HIDDEN");
# Ignore undefined symbols.
next if ($ndx eq "UND");
# Error out for unhandled cases.
if ($bind !~ /^(GLOBAL|WEAK)/ or $vis ne "DEFAULT") {
die "unhandled symbol:\n$_";
}
# Remember symbol.
$sym_hash{$name}++;
}
close READELF or die "readelf error";
}
##########
# The various types of glob patterns.
#
# A glob pattern that is to be applied to the demangled name: 'cxx'.
# A glob patterns that applies directly to the name in the .o files: 'glob'.
# This pattern is ignored; used for local variables (usually just '*'): 'ign'.
# The type of the current pattern.
my $glob = 'glob';
# We're currently inside `extern "C++"', which Sun ld doesn't understand.
my $in_extern = 0;
# The c++filt command to use. This *must* be GNU c++filt; the Sun Studio
# c++filt doesn't handle the GNU mangling style.
my $cxxfilt = $ENV{'CXXFILT'} || "c++filt";
# The current version name.
my $current_version = "";
# Was there any attempt to match a symbol to this version?
my $matches_attempted;
# The number of versions which matched this symbol.
my $matched_symbols;
open F,$symvers or die $!;
# Print information about generating this file
print "# This file was generated by make_sunver.pl. DO NOT EDIT!\n";
print "# It was generated by:\n";
printf "# %s %s %s\n", $0, $symvers, (join ' ',@ARGV);
printf "# Omitted archives with corresponding shared libraries: %s\n",
(join ' ', @SHAREDOBJS) if $#SHAREDOBJS >= 0;
print "#\n\n";
print "\$mapfile_version 2\n";
while (<F>) {
# Lines of the form '};'
if (/^([ \t]*)(\}[ \t]*;[ \t]*)$/) {
$glob = 'glob';
if ($in_extern) {
$in_extern--;
print "$1##$2\n";
} else {
print;
}
next;
}
# Lines of the form '} SOME_VERSION_NAME_1.0;'
if (/^[ \t]*\}[ \tA-Z0-9_.a-z]+;[ \t]*$/) {
$glob = 'glob';
# We tried to match symbols agains this version, but none matched.
# Emit dummy hidden symbol to avoid marking this version WEAK.
if ($matches_attempted && $matched_symbols == 0) {
print " hidden:\n";
print " .force_WEAK_off_$current_version = DATA S0x0 V0x0;\n";
}
print; next;
}
# Comment and blank lines
if (/^[ \t]*\#/) { print; next; }
if (/^[ \t]*$/) { print; next; }
# Lines of the form '{'
if (/^([ \t]*){$/) {
if ($in_extern) {
print "$1##{\n";
} else {
print;
}
next;
}
# Lines of the form 'SOME_VERSION_NAME_1.1 {'
if (/^([A-Z0-9_.]+)[ \t]+{$/) {
# Record version name.
$current_version = $1;
# Reset match attempts, #matched symbols for this version.
$matches_attempted = 0;
$matched_symbols = 0;
print "SYMBOL_VERSION $1 {\n";
next;
}
# Ignore 'global:'
if (/^[ \t]*global:$/) { print; next; }
# After 'local:', globs should be ignored, they won't be exported.
if (/^[ \t]*local:$/) {
$glob = 'ign';
print;
next;
}
# After 'extern "C++"', globs are C++ patterns
if (/^([ \t]*)(extern \"C\+\+\"[ \t]*)$/) {
$in_extern++;
$glob = 'cxx';
# Need to comment, Sun ld cannot handle this.
print "$1##$2\n"; next;
}
# Chomp newline now we're done with passing through the input file.
chomp;
# Catch globs. Note that '{}' is not allowed in globs by this script,
# so only '*' and '[]' are available.
if (/^([ \t]*)([^ \t;{}#]+);?[ \t]*$/) {
my $ws = $1;
my $ptn = $2;
# Turn the glob into a regex by replacing '*' with '.*', '?' with '.'.
# Keep $ptn so we can still print the original form.
($pattern = $ptn) =~ s/\*/\.\*/g;
$pattern =~ s/\?/\./g;
if ($glob eq 'ign') {
# We're in a local: * section; just continue.
print "$_\n";
next;
}
# Print the glob commented for human readers.
print "$ws##$ptn ($glob)\n";
# We tried to match a symbol to this version.
$matches_attempted++;
if ($glob eq 'glob') {
my %ptn_syms = ();
# Match ptn against symbols in %sym_hash.
foreach my $sym (keys %sym_hash) {
# Maybe it matches one of the patterns based on the symbol in
# the .o file.
$ptn_syms{$sym}++ if ($sym =~ /^$pattern$/);
}
foreach my $sym (sort keys(%ptn_syms)) {
$matched_symbols++;
print "$ws$sym;\n";
}
} elsif ($glob eq 'cxx') {
my %dem_syms = ();
# Verify that we're actually using GNU c++filt. Other versions
# most likely cannot handle GNU style symbol mangling.
my $cxxout = `$cxxfilt --version 2>&1`;
$cxxout =~ m/GNU/ or die "$0 requires GNU c++filt to function";
# Talk to c++filt through a pair of file descriptors.
# Need to start a fresh instance per pattern, otherwise the
# process grows to 500+ MB.
my $pid = open2(*FILTIN, *FILTOUT, $cxxfilt) or die $!;
# Match ptn against symbols in %sym_hash.
foreach my $sym (keys %sym_hash) {
# No? Well, maybe its demangled form matches one of those
# patterns.
printf FILTOUT "%s\n",$sym;
my $dem = <FILTIN>;
chomp $dem;
$dem_syms{$sym}++ if ($dem =~ /^$pattern$/);
}
close FILTOUT or die "c++filt error";
close FILTIN or die "c++filt error";
# Need to wait for the c++filt process to avoid lots of zombies.
waitpid $pid, 0;
foreach my $sym (sort keys(%dem_syms)) {
$matched_symbols++;
print "$ws$sym;\n";
}
} else {
# No? Well, then ignore it.
}
next;
}
# Important sanity check. This script can't handle lots of formats
# that GNU ld can, so be sure to error out if one is seen!
die "strange line `$_'";
}
close F;

View File

@ -16,8 +16,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FFMPEG_COMPAT_TMS470_MATH_H
#define FFMPEG_COMPAT_TMS470_MATH_H
#ifndef COMPAT_TMS470_MATH_H
#define COMPAT_TMS470_MATH_H
#include_next <math.h>
@ -27,4 +27,4 @@
#define INFINITY (*(const float*)((const unsigned []){ 0x7f800000 }))
#define NAN (*(const float*)((const unsigned []){ 0x7fc00000 }))
#endif /* FFMPEG_COMPAT_TMS470_MATH_H */
#endif /* COMPAT_TMS470_MATH_H */

View File

@ -19,6 +19,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef COMPAT_VA_COPY_H
#define COMPAT_VA_COPY_H
#include <stdarg.h>
#if !defined(va_copy) && defined(_MSC_VER)
@ -27,3 +30,5 @@
#if !defined(va_copy) && defined(__GNUC__) && __GNUC__ < 3
#define va_copy(dst, src) __va_copy(dst, src)
#endif
#endif /* COMPAT_VA_COPY_H */

View File

@ -26,8 +26,8 @@
* w32threads to pthreads wrapper
*/
#ifndef FFMPEG_COMPAT_W32PTHREADS_H
#define FFMPEG_COMPAT_W32PTHREADS_H
#ifndef COMPAT_W32PTHREADS_H
#define COMPAT_W32PTHREADS_H
/* Build up a pthread-like API using underlying Windows API. Have only static
* methods so as to not conflict with a potentially linked in pthread-win32
@ -39,6 +39,11 @@
#include <windows.h>
#include <process.h>
#if _WIN32_WINNT < 0x0600 && defined(__MINGW32__)
#undef MemoryBarrier
#define MemoryBarrier __sync_synchronize
#endif
#include "libavutil/attributes.h"
#include "libavutil/common.h"
#include "libavutil/internal.h"
@ -82,19 +87,29 @@ static av_unused int pthread_create(pthread_t *thread, const void *unused_attr,
{
thread->func = start_routine;
thread->arg = arg;
#if HAVE_WINRT
thread->handle = (void*)CreateThread(NULL, 0, win32thread_worker, thread,
0, NULL);
#else
thread->handle = (void*)_beginthreadex(NULL, 0, win32thread_worker, thread,
0, NULL);
#endif
return !thread->handle;
}
static av_unused void pthread_join(pthread_t thread, void **value_ptr)
static av_unused int pthread_join(pthread_t thread, void **value_ptr)
{
DWORD ret = WaitForSingleObject(thread.handle, INFINITE);
if (ret != WAIT_OBJECT_0)
return;
if (ret != WAIT_OBJECT_0) {
if (ret == WAIT_ABANDONED)
return EINVAL;
else
return EDEADLK;
}
if (value_ptr)
*value_ptr = thread.ret;
CloseHandle(thread.handle);
return 0;
}
static inline int pthread_mutex_init(pthread_mutex_t *m, void* attr)
@ -119,6 +134,19 @@ static inline int pthread_mutex_unlock(pthread_mutex_t *m)
}
#if _WIN32_WINNT >= 0x0600
typedef INIT_ONCE pthread_once_t;
#define PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT
static av_unused int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
{
BOOL pending = FALSE;
InitOnceBeginInitialize(once_control, 0, &pending, NULL);
if (pending)
init_routine();
InitOnceComplete(once_control, 0, NULL);
return 0;
}
static inline int pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
{
InitializeConditionVariable(cond);
@ -126,14 +154,15 @@ static inline int pthread_cond_init(pthread_cond_t *cond, const void *unused_att
}
/* native condition variables do not destroy */
static inline void pthread_cond_destroy(pthread_cond_t *cond)
static inline int pthread_cond_destroy(pthread_cond_t *cond)
{
return;
return 0;
}
static inline void pthread_cond_broadcast(pthread_cond_t *cond)
static inline int pthread_cond_broadcast(pthread_cond_t *cond)
{
WakeAllConditionVariable(cond);
return 0;
}
static inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
@ -142,14 +171,77 @@ static inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex
return 0;
}
static inline void pthread_cond_signal(pthread_cond_t *cond)
static inline int pthread_cond_signal(pthread_cond_t *cond)
{
WakeConditionVariable(cond);
return 0;
}
#else // _WIN32_WINNT < 0x0600
/* atomic init state of dynamically loaded functions */
static LONG w32thread_init_state = 0;
static av_unused void w32thread_init(void);
/* for pre-Windows 6.0 platforms, define INIT_ONCE struct,
* compatible to the one used in the native API */
typedef union pthread_once_t {
void * Ptr; ///< For the Windows 6.0+ native functions
LONG state; ///< For the pre-Windows 6.0 compat code
} pthread_once_t;
#define PTHREAD_ONCE_INIT {0}
/* function pointers to init once API on windows 6.0+ kernels */
static BOOL (WINAPI *initonce_begin)(pthread_once_t *lpInitOnce, DWORD dwFlags, BOOL *fPending, void **lpContext);
static BOOL (WINAPI *initonce_complete)(pthread_once_t *lpInitOnce, DWORD dwFlags, void *lpContext);
/* pre-Windows 6.0 compat using a spin-lock */
static inline void w32thread_once_fallback(LONG volatile *state, void (*init_routine)(void))
{
switch (InterlockedCompareExchange(state, 1, 0)) {
/* Initial run */
case 0:
init_routine();
InterlockedExchange(state, 2);
break;
/* Another thread is running init */
case 1:
while (1) {
MemoryBarrier();
if (*state == 2)
break;
Sleep(0);
}
break;
/* Initialization complete */
case 2:
break;
}
}
static av_unused int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
{
w32thread_once_fallback(&w32thread_init_state, w32thread_init);
/* Use native functions on Windows 6.0+ */
if (initonce_begin && initonce_complete) {
BOOL pending = FALSE;
initonce_begin(once_control, 0, &pending, NULL);
if (pending)
init_routine();
initonce_complete(once_control, 0, NULL);
return 0;
}
w32thread_once_fallback(&once_control->state, init_routine);
return 0;
}
/* for pre-Windows 6.0 platforms we need to define and use our own condition
* variable and api */
typedef struct win32_cond_t {
pthread_mutex_t mtx_broadcast;
pthread_mutex_t mtx_waiter_count;
@ -169,6 +261,9 @@ static BOOL (WINAPI *cond_wait)(pthread_cond_t *cond, pthread_mutex_t *mutex,
static av_unused int pthread_cond_init(pthread_cond_t *cond, const void *unused_attr)
{
win32_cond_t *win32_cond = NULL;
w32thread_once_fallback(&w32thread_init_state, w32thread_init);
if (cond_init) {
cond_init(cond);
return 0;
@ -191,12 +286,12 @@ static av_unused int pthread_cond_init(pthread_cond_t *cond, const void *unused_
return 0;
}
static av_unused void pthread_cond_destroy(pthread_cond_t *cond)
static av_unused int pthread_cond_destroy(pthread_cond_t *cond)
{
win32_cond_t *win32_cond = cond->Ptr;
/* native condition variables do not destroy */
if (cond_init)
return;
return 0;
/* non native condition variables */
CloseHandle(win32_cond->semaphore);
@ -205,16 +300,17 @@ static av_unused void pthread_cond_destroy(pthread_cond_t *cond)
pthread_mutex_destroy(&win32_cond->mtx_broadcast);
av_freep(&win32_cond);
cond->Ptr = NULL;
return 0;
}
static av_unused void pthread_cond_broadcast(pthread_cond_t *cond)
static av_unused int pthread_cond_broadcast(pthread_cond_t *cond)
{
win32_cond_t *win32_cond = cond->Ptr;
int have_waiter;
if (cond_broadcast) {
cond_broadcast(cond);
return;
return 0;
}
/* non native condition variables */
@ -236,6 +332,7 @@ static av_unused void pthread_cond_broadcast(pthread_cond_t *cond)
} else
pthread_mutex_unlock(&win32_cond->mtx_waiter_count);
pthread_mutex_unlock(&win32_cond->mtx_broadcast);
return 0;
}
static av_unused int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
@ -270,13 +367,13 @@ static av_unused int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu
return pthread_mutex_lock(mutex);
}
static av_unused void pthread_cond_signal(pthread_cond_t *cond)
static av_unused int pthread_cond_signal(pthread_cond_t *cond)
{
win32_cond_t *win32_cond = cond->Ptr;
int have_waiter;
if (cond_signal) {
cond_signal(cond);
return;
return 0;
}
pthread_mutex_lock(&win32_cond->mtx_broadcast);
@ -293,6 +390,7 @@ static av_unused void pthread_cond_signal(pthread_cond_t *cond)
}
pthread_mutex_unlock(&win32_cond->mtx_broadcast);
return 0;
}
#endif
@ -309,8 +407,12 @@ static av_unused void w32thread_init(void)
(void*)GetProcAddress(kernel_dll, "WakeConditionVariable");
cond_wait =
(void*)GetProcAddress(kernel_dll, "SleepConditionVariableCS");
initonce_begin =
(void*)GetProcAddress(kernel_dll, "InitOnceBeginInitialize");
initonce_complete =
(void*)GetProcAddress(kernel_dll, "InitOnceComplete");
#endif
}
#endif /* FFMPEG_COMPAT_W32PTHREADS_H */
#endif /* COMPAT_W32PTHREADS_H */

643
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -2,19 +2,120 @@ Never assume the API of libav* to be stable unless at least 1 month has passed
since the last major version increase or the API was added.
The last version increases were:
libavcodec: 2014-08-09
libavdevice: 2014-08-09
libavfilter: 2014-08-09
libavformat: 2014-08-09
libavresample: 2014-08-09
libpostproc: 2014-08-09
libswresample: 2014-08-09
libswscale: 2014-08-09
libavutil: 2014-08-09
libavcodec: 2015-08-28
libavdevice: 2015-08-28
libavfilter: 2015-08-28
libavformat: 2015-08-28
libavresample: 2015-08-28
libpostproc: 2015-08-28
libswresample: 2015-08-28
libswscale: 2015-08-28
libavutil: 2015-08-28
API changes, most recent first:
-------- 8< --------- FFmpeg 3.0 was cut here -------- 8< ---------
2016-02-10 - bc9a596 / 9f61abc - lavf 57.25.100 / 57.3.0 - avformat.h
Add AVFormatContext.opaque, io_open and io_close, allowing custom IO
2016-02-01 - 1dba837 - lavf 57.24.100 - avformat.h, avio.h
Add protocol_whitelist to AVFormatContext, AVIOContext
2016-01-31 - 66e9d2f - lavu 55.17.100 - frame.h
Add AV_FRAME_DATA_GOP_TIMECODE for exporting MPEG1/2 GOP timecodes.
2016-01-01 - 5e8b053 / 2c68113 - lavc 57.21.100 / 57.12.0 - avcodec.h
Add AVCodecDescriptor.profiles and avcodec_profile_name().
2015-12-28 - 1f9139b - lavf 57.21.100 - avformat.h
Add automatic bitstream filtering; add av_apply_bitstream_filters()
2015-12-22 - 39a09e9 - lavfi 6.21.101 - avfilter.h
Deprecate avfilter_link_set_closed().
Applications are not supposed to mess with links,
they should close the sinks.
2015-12-17 - lavc 57.18.100 / 57.11.0 - avcodec.h dirac.h
xxxxxxx - Add av_packet_add_side_data().
xxxxxxx - Add AVCodecContext.coded_side_data.
xxxxxxx - Add AVCPBProperties API.
xxxxxxx - Add a new public header dirac.h containing
av_dirac_parse_sequence_header()
2015-12-11 - 676a93f - lavf 57.20.100 - avformat.h
Add av_program_add_stream_index()
2015-11-29 - 93fb4a4 - lavc 57.16.101 - avcodec.h
Deprecate rtp_callback without replacement, i.e. it won't be possible to
get image slices before the full frame is encoded any more. The libavformat
rtpenc muxer can still be used for RFC-2190 packetization.
2015-11-22 - fe20e34 - lavc 57.16.100 - avcodec.h
Add AV_PKT_DATA_FALLBACK_TRACK for making fallback associations between
streams.
2015-11-22 - ad317c9 - lavf 57.19.100 - avformat.h
Add av_stream_new_side_data().
2015-11-22 - e12f403 - lavu 55.8.100 - xtea.h
Add av_xtea_le_init and av_xtea_le_crypt
2015-11-18 - lavu 55.7.100 - mem.h
Add av_fast_mallocz()
2015-10-29 - lavc 57.12.100 / 57.8.0 - avcodec.h
xxxxxx - Deprecate av_free_packet(). Use av_packet_unref() as replacement,
it resets the packet in a more consistent way.
xxxxxx - Deprecate av_dup_packet(), it is a no-op for most cases.
Use av_packet_ref() to make a non-refcounted AVPacket refcounted.
xxxxxx - Add av_packet_alloc(), av_packet_clone(), av_packet_free().
They match the AVFrame functions with the same name.
2015-10-27 - 1e477a9 - lavu 55.5.100 - cpu.h
Add AV_CPU_FLAG_AESNI.
2015-10-22 - ee573b4 / a17a766 - lavc 57.9.100 / 57.5.0 - avcodec.h
Add data and linesize array to AVSubtitleRect, to be used instead of
the ones from the embedded AVPicture.
2015-10-22 - 866a417 / dc923bc - lavc 57.8.100 / 57.0.0 - qsv.h
Add an API for allocating opaque surfaces.
2015-10-15 - 2c2d162 - lavf 57.4.100
Remove the latm demuxer that was a duplicate of the loas demuxer.
2015-10-14 - b994788 / 11c5f43 - lavu 55.4.100 / 55.2.0 - dict.h
Change return type of av_dict_copy() from void to int, so that a proper
error code can be reported.
2015-09-29 - b01891a / 948f3c1 - lavc 57.3.100 / 57.2.0 - avcodec.h
Change type of AVPacket.duration from int to int64_t.
2015-09-17 - 7c46f24 / e3d4784 - lavc 57.3.100 / 57.2.0 - d3d11va.h
Add av_d3d11va_alloc_context(). This function must from now on be used for
allocating AVD3D11VAContext.
2015-09-15 - lavf 57.2.100 - avformat.h
probesize and max_analyze_duration switched to 64bit, both
are only accessible through AVOptions
2015-09-15 - lavf 57.1.100 - avformat.h
bit_rate was changed to 64bit, make sure you update any
printf() or other type sensitive code
2015-09-15 - lavc 57.2.100 - avcodec.h
bit_rate/rc_max_rate/rc_min_rate were changed to 64bit, make sure you update
any printf() or other type sensitive code
2015-09-07 - lavu 55.0.100 / 55.0.0
c734b34 / b8b5d82 - Change type of AVPixFmtDescriptor.flags from uint8_t to uint64_t.
f53569a / 6b3ef7f - Change type of AVComponentDescriptor fields from uint16_t to int
and drop bit packing.
151aa2e / 2268db2 - Add step, offset, and depth to AVComponentDescriptor to replace
the deprecated step_minus1, offset_plus1, and depth_minus1.
-------- 8< --------- FFmpeg 2.8 was cut here -------- 8< ---------
2015-08-27 - 1dd854e1 - lavc 56.58.100 - vaapi.h
@ -1020,15 +1121,14 @@ lavd 54.4.100 / 54.0.0, lavfi 3.5.0
Add avresample_set_channel_mapping() for input channel reordering,
duplication, and silencing.
2012-12-29 - 2ce43b3 / d8fd06c - lavu 52.13.100 / 52.3.0 - avstring.h
Add av_basename() and av_dirname().
2012-12-29 - lavu 52.13.100 / 52.3.0 - avstring.h
2ce43b3 / d8fd06c - Add av_basename() and av_dirname().
e13d5e9 / c1a02e8 - Add av_pix_fmt_get_chroma_sub_sample and deprecate
avcodec_get_chroma_sub_sample.
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 - 7d26be6 / dfde8a3 - lavu 52.5.100 / 52.1.0 - intmath.h
Add av_ctz() for trailing zero bit count
2012-10-21 - e3a91c5 / a893655 - lavu 51.77.100 / 51.45.0 - error.h
Add AVERROR_EXPERIMENTAL

View File

@ -31,7 +31,7 @@ PROJECT_NAME = FFmpeg
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = 2.8.6
PROJECT_NUMBER = 3.0
# With the PROJECT_LOGO tag one can specify a logo or icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
@ -1360,6 +1360,7 @@ PREDEFINED = "__attribute__(x)=" \
"offsetof(x,y)=0x42" \
av_alloc_size \
AV_GCC_VERSION_AT_LEAST(x,y)=1 \
AV_GCC_VERSION_AT_MOST(x,y)=0 \
__GNUC__=1 \
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then

View File

@ -124,11 +124,12 @@ $(DOCS) doc/doxy/html: | doc/
$(DOC_EXAMPLES:%$(EXESUF)=%.o): | doc/examples
OBJDIRS += doc/examples
DOXY_INPUT = $(addprefix $(SRC_PATH)/, $(INSTHEADERS) $(DOC_EXAMPLES:%$(EXESUF)=%.c) $(LIB_EXAMPLES:%$(EXESUF)=%.c))
DOXY_INPUT = $(INSTHEADERS) $(DOC_EXAMPLES:%$(EXESUF)=%.c) $(LIB_EXAMPLES:%$(EXESUF)=%.c)
DOXY_INPUT_DEPS = $(addprefix $(SRC_PATH)/, $(DOXY_INPUT))
doc/doxy/html: TAG = DOXY
doc/doxy/html: $(SRC_PATH)/doc/Doxyfile $(SRC_PATH)/doc/doxy-wrapper.sh $(DOXY_INPUT)
$(M)$(SRC_PATH)/doc/doxy-wrapper.sh $(SRC_PATH) $< $(DOXYGEN) $(DOXY_INPUT)
doc/doxy/html: $(SRC_PATH)/doc/Doxyfile $(SRC_PATH)/doc/doxy-wrapper.sh $(DOXY_INPUT_DEPS)
$(M)OUT_DIR=$$PWD/doc/doxy; cd $(SRC_PATH); ./doc/doxy-wrapper.sh $$OUT_DIR $< $(DOXYGEN) $(DOXY_INPUT);
install-doc: install-html install-man

View File

@ -9,7 +9,7 @@ V
DBG
Preprocess x86 external assembler files to a .dbg.asm file in the object
directory, which then gets compiled. Helps developping those assembler
directory, which then gets compiled. Helps in developing those assembler
files.
DESTDIR
@ -25,10 +25,10 @@ all
Default target, builds all the libraries and the executables.
fate
Run the fate test suite, note you must have installed it
Run the fate test suite, note that you must have installed it.
fate-list
Will list all fate/regression test targets
List all fate/regression test targets.
install
Install headers, libraries and programs.
@ -43,22 +43,22 @@ libavcodec/api-example
Build the libavcodec basic example.
libswscale/swscale-test
Build the swscale self-test (useful also as example).
Build the swscale self-test (useful also as an example).
config
Reconfigure the project with current configuration.
Reconfigure the project with the current configuration.
Useful standard make commands:
make -t <target>
Touch all files that otherwise would be build, this is useful to reduce
unneeded rebuilding when changing headers, but note you must force rebuilds
Touch all files that otherwise would be built, this is useful to reduce
unneeded rebuilding when changing headers, but note that 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
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.
Continue build in case of errors, this is useful for the regression tests
sometimes but note that it will still not run all reg tests.

View File

@ -129,7 +129,7 @@ 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.
Set the group of picture (GOP) size. Default value is 12.
@item ar @var{integer} (@emph{decoding/encoding,audio})
Set audio sampling rate (in Hz).
@ -817,13 +817,17 @@ for codecs that support it. See also @file{doc/examples/export_mvs.c}.
Deprecated, use mpegvideo private options instead.
@item threads @var{integer} (@emph{decoding/encoding,video})
Set the number of threads to be used, in case the selected codec
implementation supports multi-threading.
Possible values:
@table @samp
@item auto
detect a good number of threads
@item auto, 0
automatically select the number of threads to set
@end table
Default value is @samp{auto}.
@item me_threshold @var{integer} (@emph{encoding,video})
Set motion estimation threshold.

View File

@ -282,7 +282,13 @@ Sets the display duration of the decoded teletext pages or subtitles in
miliseconds. Default value is 30000 which is 30 seconds.
@item txt_transparent
Force transparent background of the generated teletext bitmaps. Default value
is 0 which means an opaque (black) background.
is 0 which means an opaque background.
@item txt_opacity
Sets the opacity (0-255) of the teletext background. If
@option{txt_transparent} is not set, it only affects characters between a start
box and an end box, typically subtitles. Default value is 0 if
@option{txt_transparent} is set, 255 otherwise.
@end table
@c man end SUBTILES DECODERS

View File

@ -204,8 +204,43 @@ Currently, the only conversion is adding the h264_mp4toannexb bitstream
filter to H.264 streams in MP4 format. This is necessary in particular if
there are resolution changes.
@item segment_time_metadata
If set to 1, every packet will contain the @var{lavf.concat.start_time} and the
@var{lavf.concat.duration} packet metadata values which are the start_time and
the duration of the respective file segments in the concatenated output
expressed in microseconds. The duration metadata is only set if it is known
based on the concat file.
The default is 0.
@end table
@subsection Examples
@itemize
@item
Use absolute filenames and include some comments:
@example
# my first filename
file /mnt/share/file-1.wav
# my second filename including whitespace
file '/mnt/share/file 2.wav'
# my third filename including whitespace plus single quote
file '/mnt/share/file 3'\''.wav'
@end example
@item
Allow for input format auto-probing, use safe filenames and set the duration of
the first file:
@example
ffconcat version 1.0
file file-1.wav
duration 20.0
file subdir/file-2.wav
@end example
@end itemize
@section flv
Adobe Flash Video Format demuxer.
@ -230,18 +265,6 @@ track. Track indexes start at 0. The demuxer exports the number of tracks as
For very large files, the @option{max_size} option may have to be adjusted.
@section libquvi
Play media from Internet services using the quvi project.
The demuxer accepts a @option{format} option to request a specific quality. It
is by default set to @var{best}.
See @url{http://quvi.sourceforge.net/} for more information.
FFmpeg needs to be built with @code{--enable-libquvi} for this demuxer to be
enabled.
@section gif
Animated GIF demuxer.
@ -459,6 +482,21 @@ to 1 (-1 means automatic setting, 1 means enabled, 0 means
disabled). Default value is -1.
@end table
@section mpjpeg
MJPEG encapsulated in multi-part MIME demuxer.
This demuxer allows reading of MJPEG, where each frame is represented as a part of
multipart/x-mixed-replace stream.
@table @option
@item strict_mime_boundary
Default implementation applies a relaxed standard to multi-part MIME boundary detection,
to prevent regression with numerous existing endpoints not generating a proper MIME
MJPEG stream. Turning this option on by setting it to 1 will result in a stricter check
of the boundary value.
@end table
@section rawvideo
Raw video demuxer.

View File

@ -28,14 +28,14 @@ this document.
For more detailed legal information about the use of FFmpeg in
external programs read the @file{LICENSE} file in the source tree and
consult @url{http://ffmpeg.org/legal.html}.
consult @url{https://ffmpeg.org/legal.html}.
@section Contributing
There are 3 ways by which code gets into ffmpeg.
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 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.
@ -65,6 +65,9 @@ rejected by the git repository.
@item
You should try to limit your code lines to 80 characters; however, do so if
and only if this improves readability.
@item
K&R coding style is used.
@end itemize
The presentation is one inspired by 'indent -i4 -kr -nut'.
@ -124,10 +127,10 @@ the @samp{inline} keyword;
@samp{//} comments;
@item
designated struct initializers (@samp{struct s x = @{ .i = 17 @};})
designated struct initializers (@samp{struct s x = @{ .i = 17 @};});
@item
compound literals (@samp{x = (struct s) @{ 17, 23 @};})
compound literals (@samp{x = (struct s) @{ 17, 23 @};}).
@end itemize
These features are supported by all compilers we care about, so we will not
@ -156,7 +159,7 @@ GCC statement expressions (@samp{(x = (@{ int y = 4; y; @})}).
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 exception from this are type names, like
for example structs and enums; they should always be in the CamelCase
for example structs and enums; they should always be in CamelCase.
There are the following conventions for naming variables and functions:
@ -394,8 +397,8 @@ or obfuscates the code.
Make sure that no parts of the codebase that you maintain are missing from the
@file{MAINTAINERS} file. If something that you want to maintain is missing add it with
your name after it.
If at some point you no longer want to maintain some code, then please help
finding a new maintainer and also don't forget updating the @file{MAINTAINERS} file.
If at some point you no longer want to maintain some code, then please help in
finding a new maintainer and also don't forget to update the @file{MAINTAINERS} file.
@end enumerate
We think our rules are not too hard. If you have comments, contact us.
@ -407,7 +410,7 @@ First, read the @ref{Coding Rules} above if you did not yet, in particular
the rules regarding patch submission.
When you submit your patch, please use @code{git format-patch} or
@code{git send-email}. We cannot read other diffs :-)
@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
@ -430,7 +433,7 @@ 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{http://lists.ffmpeg.org/mailman/listinfo/ffmpeg-devel, ffmpeg-devel}
@uref{https://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
@ -545,7 +548,7 @@ amounts of memory when fed damaged data.
@item
Did you test your decoder or demuxer against sample files?
Samples may be obtained at @url{http://samples.ffmpeg.org}.
Samples may be obtained at @url{https://samples.ffmpeg.org}.
@item
Does the patch not mix functional and cosmetic changes?
@ -567,7 +570,7 @@ If the patch fixes a bug, did you provide a verbose analysis of the bug?
If the patch fixes a bug, did you provide enough information, including
a sample, so the bug can be reproduced and the fix can be verified?
Note please do not attach samples >100k to mails but rather provide a
URL, you can upload to ftp://upload.ffmpeg.org
URL, you can upload to ftp://upload.ffmpeg.org.
@item
Did you provide a verbose summary about what the patch does change?
@ -596,10 +599,10 @@ Lines with similar content should be aligned vertically when doing so
improves readability.
@item
Consider to add a regression test for your code.
Consider adding a regression test for your code.
@item
If you added YASM code please check that things still work with --disable-yasm
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
@ -664,7 +667,6 @@ Once you have a working fate test and fate sample, provide in the commit
message or introductory message for the patch series that you post to
the ffmpeg-devel mailing list, a direct link to download the sample media.
@subsection Visualizing Test Coverage
The FFmpeg build system allows visualizing the test coverage in an easy
@ -712,7 +714,7 @@ FFmpeg maintains a set of @strong{release branches}, which are the
recommended deliverable for system integrators and distributors (such as
Linux distributions, etc.). At regular times, a @strong{release
manager} prepares, tests and publishes tarballs on the
@url{http://ffmpeg.org} website.
@url{https://ffmpeg.org} website.
There are two kinds of releases:
@ -791,7 +793,7 @@ 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://ffmpeg.org/releases}. Create and
Publish the tarballs at @url{https://ffmpeg.org/releases}. Create and
push an annotated tag in the form @code{nX}, with @code{X}
containing the version number.
@ -803,7 +805,7 @@ with a news entry for the website.
Publish the news entry.
@item
Send announcement to the mailing list.
Send an announcement to the mailing list.
@end enumerate
@bye

View File

@ -1,21 +1,21 @@
#!/bin/sh
SRC_PATH="${1}"
OUT_DIR="${1}"
DOXYFILE="${2}"
DOXYGEN="${3}"
shift 3
if [ -e "$SRC_PATH/VERSION" ]; then
VERSION=`cat "$SRC_PATH/VERSION"`
if [ -e "VERSION" ]; then
VERSION=`cat "VERSION"`
else
VERSION=`cd "$SRC_PATH"; git describe`
VERSION=`git describe`
fi
$DOXYGEN - <<EOF
@INCLUDE = ${DOXYFILE}
INPUT = $@
EXAMPLE_PATH = ${SRC_PATH}/doc/examples
HTML_TIMESTAMP = NO
PROJECT_NUMBER = $VERSION
OUTPUT_DIRECTORY = $OUT_DIR
EOF

View File

@ -30,81 +30,119 @@ follows.
Advanced Audio Coding (AAC) encoder.
This encoder is an experimental FFmpeg-native AAC encoder. Currently only the
low complexity (AAC-LC) profile is supported. To use this encoder, you must set
@option{strict} option to @samp{experimental} or lower.
As this encoder is experimental, unexpected behavior may exist from time to
time. For a more stable AAC encoder, see @ref{libvo-aacenc}. However, be warned
that it has a worse quality reported by some users.
@c todo @ref{libaacplus}
See also @ref{libfdk-aac-enc,,libfdk_aac} and @ref{libfaac}.
This encoder is the default AAC encoder, natively implemented into FFmpeg. Its
quality is on par or better than libfdk_aac at the default bitrate of 128kbps.
This encoder also implements more options, profiles and samplerates than
other encoders (with only the AAC-HE profile pending to be implemented) so this
encoder has become the default and is the recommended choice.
@subsection Options
@table @option
@item b
Set bit rate in bits/s. Setting this automatically activates constant bit rate
(CBR) mode.
(CBR) mode. If this option is unspecified it is set to 128kbps.
@item q
Set quality for variable bit rate (VBR) mode. This option is valid only using
the @command{ffmpeg} command-line tool. For library interface users, use
@option{global_quality}.
@item stereo_mode
Set stereo encoding mode. Possible values:
@table @samp
@item auto
Automatically selected by the encoder.
@item ms_off
Disable middle/side encoding. This is the default.
@item ms_force
Force middle/side encoding.
@end table
@item cutoff
Set cutoff frequency. If unspecified will allow the encoder to dynamically
adjust the cutoff to improve clarity on low bitrates.
@item aac_coder
Set AAC encoder coding method. Possible values:
@table @samp
@item faac
FAAC-inspired method.
This method is a simplified reimplementation of the method used in FAAC, which
sets thresholds proportional to the band energies, and then decreases all the
thresholds with quantizer steps to find the appropriate quantization with
distortion below threshold band by band.
The quality of this method is comparable to the two loop searching method
described below, but somewhat a little better and slower.
@item anmr
Average noise to mask ratio (ANMR) trellis-based solution.
This has a theoretic best quality out of all the coding methods, but at the
cost of the slowest speed.
@item twoloop
Two loop searching (TLS) method.
This method first sets quantizers depending on band thresholds and then tries
to find an optimal combination by adding or subtracting a specific value from
all quantizers and adjusting some individual quantizer a little.
Will tune itself based on whether aac_is/aac_ms/aac_pns are enabled.
This is the default choice for a coder.
This method produces similar quality with the FAAC method and is the default.
@item anmr
Average noise to mask ratio (ANMR) trellis-based solution.
This is an experimental coder which currently produces a lower quality, is more
unstable and is slower than the default twoloop coder but has potential.
Currently has no support for the @option{aac_is} or @option{aac_pns} options.
Not currently recommended.
@item fast
Constant quantizer method.
This method sets a constant quantizer for all bands. This is the fastest of all
the methods, yet produces the worst quality.
the methods and has no rate control or support for @option{aac_is} or
@option{aac_pns}.
Not recommended.
@end table
@item aac_ms
Sets mid/side coding mode. The default value of auto will automatically use
M/S with bands which will benefit from such coding. Can be forced for all bands
using the value "enable", which is mainly useful for debugging or disabled using
"disable".
@item aac_is
Sets intensity stereo coding tool usage. By default, it's enabled and will
automatically toggle IS for similar pairs of stereo bands if it's benefitial.
Can be disabled for debugging by setting the value to "disable".
@item aac_pns
Uses perceptual noise substitution to replace low entropy high frequency bands
with imperceivable white noise during the decoding process. By default, it's
enabled, but can be disabled for debugging purposes by using "disable".
@item aac_tns
Enables the use of a multitap FIR filter which spans through the high frequency
bands to hide quantization noise during the encoding process and is reverted
by the decoder. As well as decreasing unpleasant artifacts in the high range
this also reduces the entropy in the high bands and allows for more bits to
be used by the mid-low bands. By default it's enabled but can be disabled for
debugging by setting the option to "disable".
@item aac_ltp
Enables the use of the long term prediction extension which increases coding
efficiency in very low bandwidth situations such as encoding of voice or
solo piano music by extending constant harmonic peaks in bands throughout
frames. This option is implied by profile:a aac_low and is incompatible with
aac_pred. Use in conjunction with @option{-ar} to decrease the samplerate.
@item aac_pred
Enables the use of a more traditional style of prediction where the spectral
coefficients transmitted are replaced by the difference of the current
coefficients minus the previous "predicted" coefficients. In theory and sometimes
in practice this can improve quality for low to mid bitrate audio.
This option implies the aac_main profile and is incompatible with aac_ltp.
@item profile
Sets the encoding profile, possible values:
@table @samp
@item aac_low
The default, AAC "Low-complexity" profile. Is the most compatible and produces
decent quality.
@item mpeg2_aac_low
Equivalent to -profile:a aac_low -aac_pns 0. PNS was introduced with the MPEG4
specifications.
@item aac_ltp
Long term prediction profile, is enabled by and will enable the aac_ltp option.
Introduced in MPEG4.
@item aac_main
Main-type prediction profile, is enabled by and will enable the aac_pred option.
Introduced in MPEG2.
If this option is unspecified it is set to @samp{aac_low}.
@end table
@end table
@section ac3 and ac3_fixed
@ -578,16 +616,14 @@ and slightly improves compression.
libfaac AAC (Advanced Audio Coding) encoder wrapper.
Requires the presence of the libfaac headers and library during
configuration. You need to explicitly configure the build with
This encoder is of much lower quality and is more unstable than any other AAC
encoders, so it's highly recommended to instead use other encoders, like
@ref{aacenc,,the native FFmpeg AAC encoder}.
This encoder also requires the presence of the libfaac headers and library
during configuration. You need to explicitly configure the build with
@code{--enable-libfaac --enable-nonfree}.
This encoder is considered to be of higher quality with respect to the
@ref{aacenc,,the native experimental FFmpeg AAC encoder}.
For more information see the libfaac project at
@url{http://www.audiocoding.com/faac.html/}.
@subsection Options
The following shared FFmpeg codec options are recognized.
@ -694,9 +730,10 @@ configuration. You need to explicitly configure the build with
so if you allow the use of GPL, you should configure with
@code{--enable-gpl --enable-nonfree --enable-libfdk-aac}.
This encoder is considered to be of higher quality with respect to
both @ref{aacenc,,the native experimental FFmpeg AAC encoder} and
@ref{libfaac}.
This encoder is considered to produce output on par or worse at 128kbps to the
@ref{aacenc,,the native FFmpeg AAC encoder} but can often produce better
sounding audio at identical or lower bitrates and has support for the
AAC-HE profiles.
VBR encoding, enabled through the @option{vbr} or @option{flags
+qscale} options, is experimental and only works with some
@ -1038,31 +1075,6 @@ Set MPEG audio original flag when set to 1. The default value is 0
@end table
@anchor{libvo-aacenc}
@section libvo-aacenc
VisualOn AAC encoder.
Requires the presence of the libvo-aacenc headers and library during
configuration. You need to explicitly configure the build with
@code{--enable-libvo-aacenc --enable-version3}.
This encoder is considered to be worse than the
@ref{aacenc,,native experimental FFmpeg AAC encoder}, according to
multiple sources.
@subsection Options
The VisualOn AAC encoder only support encoding AAC-LC and up to 2
channels. It is also CBR-only.
@table @option
@item b
Set bit rate in bits/s.
@end table
@section libvo-amrwbenc
VisualOn Adaptive Multi-Rate Wideband encoder.
@ -1125,7 +1137,7 @@ kilobits/s.
@item vbr (@emph{vbr}, @emph{hard-cbr}, and @emph{cvbr})
Set VBR mode. The FFmpeg @option{vbr} option has the following
valid arguments, with the their @command{opusenc} equivalent options
valid arguments, with the @command{opusenc} equivalent options
in parentheses:
@table @samp
@ -1342,6 +1354,72 @@ disabled
A description of some of the currently available video encoders
follows.
@section libopenh264
Cisco libopenh264 H.264/MPEG-4 AVC encoder wrapper.
This encoder requires the presence of the libopenh264 headers and
library during configuration. You need to explicitly configure the
build with @code{--enable-libopenh264}. The library is detected using
@command{pkg-config}.
For more information about the library see
@url{http://www.openh264.org}.
@subsection Options
The following FFmpeg global options affect the configurations of the
libopenh264 encoder.
@table @option
@item b
Set the bitrate (as a number of bits per second).
@item g
Set the GOP size.
@item maxrate
Set the max bitrate (as a number of bits per second).
@item flags +global_header
Set global header in the bitstream.
@item slices
Set the number of slices, used in parallelized encoding. Default value
is 0. This is only used when @option{slice_mode} is set to
@samp{fixed}.
@item slice_mode
Set slice mode. Can assume one of the follwing possible values:
@table @samp
@item fixed
a fixed number of slices
@item rowmb
one slice per row of macroblocks
@item auto
automatic number of slices according to number of threads
@item dyn
dynamic slicing
@end table
Default value is @samp{auto}.
@item loopfilter
Enable loop filter, if set to 1 (automatically enabled). To disable
set a value of 0.
@item profile
Set profile restrictions. If set to the value of @samp{main} enable
CABAC (set the @code{SEncParamExt.iEntropyCodingModeFlag} flag to 1).
@item max_nal_size
Set maximum NAL size in bytes.
@item allow_skip_frames
Allow skipping frames to hit the target bitrate if set to 1.
@end table
@section jpeg2000
The native jpeg 2000 encoder is lossy by default, the @code{-q:v}
@ -1506,6 +1584,12 @@ follows: @code{(minrate * 100 / bitrate)}.
@item crf (@emph{end-usage=cq}, @emph{cq-level})
@item tune (@emph{tune})
@table @samp
@item psnr (@emph{psnr})
@item ssim (@emph{ssim})
@end table
@item quality, deadline (@emph{deadline})
@table @samp
@item best
@ -2011,6 +2095,10 @@ For example to specify libx264 encoding options with @command{ffmpeg}:
ffmpeg -i foo.mpg -vcodec libx264 -x264opts keyint=123:min-keyint=20 -an out.mkv
@end example
@item a53cc @var{boolean}
Import closed captions (which must be ATSC compatible format) into output.
Only the mpeg2 and h264 decoders provide these. Default is 0 (off).
@item x264-params (N.A.)
Override the x264 configuration using a :-separated list of key=value
parameters.
@ -2339,15 +2427,165 @@ configuration. You need to explicitly configure the build with
@item b
Set target video bitrate in bit/s and enable rate control.
@item threads
Set number of encoding threads.
@item kvazaar-params
Set kvazaar parameters as a list of @var{name}=@var{value} pairs separated
by commas (,). See kvazaar documentation for a list of options.
@end table
@section QSV encoders
The family of Intel QuickSync Video encoders (MPEG-2, H.264 and HEVC)
The ratecontrol method is selected as follows:
@itemize @bullet
@item
When @option{global_quality} is specified, a quality-based mode is used.
Specifically this means either
@itemize @minus
@item
@var{CQP} - constant quantizer scale, when the @option{qscale} codec flag is
also set (the @option{-qscale} ffmpeg option).
@item
@var{LA_ICQ} - intelligent constant quality with lookahead, when the
@option{look_ahead} option is also set.
@item
@var{ICQ} -- intelligent constant quality otherwise.
@end itemize
@item
Otherwise, a bitrate-based mode is used. For all of those, you should specify at
least the desired average bitrate with the @option{b} option.
@itemize @minus
@item
@var{LA} - VBR with lookahead, when the @option{look_ahead} option is specified.
@item
@var{VCM} - video conferencing mode, when the @option{vcm} option is set.
@item
@var{CBR} - constant bitrate, when @option{maxrate} is specified and equal to
the average bitrate.
@item
@var{VBR} - variable bitrate, when @option{maxrate} is specified, but is higher
than the average bitrate.
@item
@var{AVBR} - average VBR mode, when @option{maxrate} is not specified. This mode
is further configured by the @option{avbr_accuracy} and
@option{avbr_convergence} options.
@end itemize
@end itemize
Note that depending on your system, a different mode than the one you specified
may be selected by the encoder. Set the verbosity level to @var{verbose} or
higher to see the actual settings used by the QSV runtime.
Additional libavcodec global options are mapped to MSDK options as follows:
@itemize
@item
@option{g/gop_size} -> @option{GopPicSize}
@item
@option{bf/max_b_frames}+1 -> @option{GopRefDist}
@item
@option{rc_init_occupancy/rc_initial_buffer_occupancy} ->
@option{InitialDelayInKB}
@item
@option{slices} -> @option{NumSlice}
@item
@option{refs} -> @option{NumRefFrame}
@item
@option{b_strategy/b_frame_strategy} -> @option{BRefType}
@item
@option{cgop/CLOSED_GOP} codec flag -> @option{GopOptFlag}
@item
For the @var{CQP} mode, the @option{i_qfactor/i_qoffset} and
@option{b_qfactor/b_qoffset} set the difference between @var{QPP} and @var{QPI},
and @var{QPP} and @var{QPB} respectively.
@item
Setting the @option{coder} option to the value @var{vlc} will make the H.264
encoder use CAVLC instead of CABAC.
@end itemize
@section vc2
SMPTE VC-2 (previously BBC Dirac Pro). This codec was primarily aimed at
professional broadcasting but since it supports yuv420, yuv422 and yuv444 at
8 (limited range or full range), 10 or 12 bits, this makes it suitable for
other tasks which require low overhead and low compression (like screen
recording).
@subsection Options
@table @option
@item b
Sets target video bitrate. Usually that's around 1:6 of the uncompressed
video bitrate (e.g. for 1920x1080 50fps yuv422p10 that's around 400Mbps). Higher
values (close to the uncompressed bitrate) turn on lossless compression mode.
@item field_order
Enables field coding when set (e.g. to tt - top field first) for interlaced
inputs. Should increase compression with interlaced content as it splits the
fields and encodes each separately.
@item wavelet_depth
Sets the total amount of wavelet transforms to apply, between 1 and 5 (default).
Lower values reduce compression and quality. Less capable decoders may not be
able to handle values of @option{wavelet_depth} over 3.
@item wavelet_type
Sets the transform type. Currently only @var{5_3} (LeGall) and @var{9_7}
(Deslauriers-Dubuc)
are implemented, with 9_7 being the one with better compression and thus
is the default.
@item slice_width
@item slice_height
Sets the slice size for each slice. Larger values result in better compression.
For compatibility with other more limited decoders use @option{slice_width} of
32 and @option{slice_height} of 8.
@item tolerance
Sets the undershoot tolerance of the rate control system in percent. This is
to prevent an expensive search from being run.
@item qm
Sets the quantization matrix preset to use by default or when @option{wavelet_depth}
is set to 5
@itemize @minus
@item
@var{default}
Uses the default quantization matrix from the specifications, extended with
values for the fifth level. This provides a good balance between keeping detail
and omitting artifacts.
@item
@var{flat}
Use a completely zeroed out quantization matrix. This increases PSNR but might
reduce perception. Use in bogus benchmarks.
@item
@var{color}
Reduces detail but attempts to preserve color at extremely low bitrates.
@end itemize
@end table
@c man end VIDEO ENCODERS
@chapter Subtitles Encoders

View File

@ -76,7 +76,7 @@ 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
ENAMETOOLONG POSIX - ++++++ File name too long
ENAVAIL +..... No XENIX semaphores available
ENEEDAUTH .++... Need authenticator
ENETDOWN POSIX +++..+ Network is down

View File

@ -211,7 +211,7 @@ static void audio_encode_example(const char *filename)
}
if (got_output) {
fwrite(pkt.data, 1, pkt.size, f);
av_free_packet(&pkt);
av_packet_unref(&pkt);
}
}
@ -225,7 +225,7 @@ static void audio_encode_example(const char *filename)
if (got_output) {
fwrite(pkt.data, 1, pkt.size, f);
av_free_packet(&pkt);
av_packet_unref(&pkt);
}
}
fclose(f);
@ -454,7 +454,7 @@ static void video_encode_example(const char *filename, int codec_id)
if (got_output) {
printf("Write frame %3d (size=%5d)\n", i, pkt.size);
fwrite(pkt.data, 1, pkt.size, f);
av_free_packet(&pkt);
av_packet_unref(&pkt);
}
}
@ -471,7 +471,7 @@ static void video_encode_example(const char *filename, int codec_id)
if (got_output) {
printf("Write frame %3d (size=%5d)\n", i, pkt.size);
fwrite(pkt.data, 1, pkt.size, f);
av_free_packet(&pkt);
av_packet_unref(&pkt);
}
}

View File

@ -55,17 +55,11 @@ static AVPacket pkt;
static int video_frame_count = 0;
static int audio_frame_count = 0;
/* The different ways of decoding and managing data memory. You are not
* supposed to support all the modes in your application but pick the one most
* appropriate to your needs. Look for the use of api_mode in this example to
* see what are the differences of API usage between them */
enum {
API_MODE_OLD = 0, /* old method, deprecated */
API_MODE_NEW_API_REF_COUNT = 1, /* new method, using the frame reference counting */
API_MODE_NEW_API_NO_REF_COUNT = 2, /* new method, without reference counting */
};
static int api_mode = API_MODE_OLD;
/* Enable or disable frame reference counting. You are not supposed to support
* both paths in your application but pick the one most appropriate to your
* needs. Look for the use of refcount in this example to see what are the
* differences of API usage between them. */
static int refcount = 0;
static int decode_packet(int *got_frame, int cached)
{
@ -145,9 +139,9 @@ static int decode_packet(int *got_frame, int cached)
}
}
/* If we use the new API with reference counting, we own the data and need
/* If we use frame reference counting, we own the data and need
* to de-reference it when we don't use it anymore */
if (*got_frame && api_mode == API_MODE_NEW_API_REF_COUNT)
if (*got_frame && refcount)
av_frame_unref(frame);
return decoded;
@ -181,8 +175,7 @@ static int open_codec_context(int *stream_idx,
}
/* Init the decoders, with or without reference counting */
if (api_mode == API_MODE_NEW_API_REF_COUNT)
av_dict_set(&opts, "refcounted_frames", "1", 0);
av_dict_set(&opts, "refcounted_frames", refcount ? "1" : "0", 0);
if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0) {
fprintf(stderr, "Failed to open %s codec\n",
av_get_media_type_string(type));
@ -228,28 +221,19 @@ int main (int argc, char **argv)
int ret = 0, got_frame;
if (argc != 4 && argc != 5) {
fprintf(stderr, "usage: %s [-refcount=<old|new_norefcount|new_refcount>] "
"input_file video_output_file audio_output_file\n"
fprintf(stderr, "usage: %s [-refcount] input_file video_output_file audio_output_file\n"
"API example program to show how to read frames from an input file.\n"
"This program reads frames from a file, decodes them, and writes decoded\n"
"video frames to a rawvideo file named video_output_file, and decoded\n"
"audio frames to a rawaudio file named audio_output_file.\n\n"
"If the -refcount option is specified, the program use the\n"
"reference counting frame system which allows keeping a copy of\n"
"the data for longer than one decode call. If unset, it's using\n"
"the classic old method.\n"
"the data for longer than one decode call.\n"
"\n", argv[0]);
exit(1);
}
if (argc == 5) {
const char *mode = argv[1] + strlen("-refcount=");
if (!strcmp(mode, "old")) api_mode = API_MODE_OLD;
else if (!strcmp(mode, "new_norefcount")) api_mode = API_MODE_NEW_API_NO_REF_COUNT;
else if (!strcmp(mode, "new_refcount")) api_mode = API_MODE_NEW_API_REF_COUNT;
else {
fprintf(stderr, "unknow mode '%s'\n", mode);
exit(1);
}
if (argc == 5 && !strcmp(argv[1], "-refcount")) {
refcount = 1;
argv++;
}
src_filename = argv[1];
@ -315,12 +299,7 @@ int main (int argc, char **argv)
goto end;
}
/* When using the new API, you need to use the libavutil/frame.h API, while
* the classic frame management is available in libavcodec */
if (api_mode == API_MODE_OLD)
frame = avcodec_alloc_frame();
else
frame = av_frame_alloc();
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate frame\n");
ret = AVERROR(ENOMEM);
@ -347,7 +326,7 @@ int main (int argc, char **argv)
pkt.data += ret;
pkt.size -= ret;
} while (pkt.size > 0);
av_free_packet(&orig_pkt);
av_packet_unref(&orig_pkt);
}
/* flush cached frames */
@ -397,10 +376,7 @@ end:
fclose(video_dst_file);
if (audio_dst_file)
fclose(audio_dst_file);
if (api_mode == API_MODE_OLD)
avcodec_free_frame(&frame);
else
av_frame_free(&frame);
av_frame_free(&frame);
av_free(video_dst_data[0]);
return ret < 0;

View File

@ -167,7 +167,7 @@ int main(int argc, char **argv)
pkt.data += ret;
pkt.size -= ret;
} while (pkt.size > 0);
av_free_packet(&orig_pkt);
av_packet_unref(&orig_pkt);
}
/* flush cached frames */

View File

@ -33,7 +33,6 @@
#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>
@ -274,10 +273,10 @@ int main(int argc, char **argv)
}
if (packet.size <= 0)
av_free_packet(&packet0);
av_packet_unref(&packet0);
} else {
/* discard non-wanted packets */
av_free_packet(&packet0);
av_packet_unref(&packet0);
}
}
end:

View File

@ -33,7 +33,6 @@
#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>
@ -263,7 +262,7 @@ int main(int argc, char **argv)
av_frame_unref(frame);
}
}
av_free_packet(&packet);
av_packet_unref(&packet);
}
end:
avfilter_graph_free(&filter_graph);

View File

@ -493,44 +493,25 @@ static int write_video_frame(AVFormatContext *oc, OutputStream *ost)
AVCodecContext *c;
AVFrame *frame;
int got_packet = 0;
AVPacket pkt = { 0 };
c = ost->st->codec;
frame = get_video_frame(ost);
if (oc->oformat->flags & AVFMT_RAWPICTURE) {
/* a hack to avoid data copy with some raw video muxers */
AVPacket pkt;
av_init_packet(&pkt);
av_init_packet(&pkt);
if (!frame)
return 1;
/* encode the image */
ret = avcodec_encode_video2(c, &pkt, frame, &got_packet);
if (ret < 0) {
fprintf(stderr, "Error encoding video frame: %s\n", av_err2str(ret));
exit(1);
}
pkt.flags |= AV_PKT_FLAG_KEY;
pkt.stream_index = ost->st->index;
pkt.data = (uint8_t *)frame;
pkt.size = sizeof(AVPicture);
pkt.pts = pkt.dts = frame->pts;
av_packet_rescale_ts(&pkt, c->time_base, ost->st->time_base);
ret = av_interleaved_write_frame(oc, &pkt);
if (got_packet) {
ret = write_frame(oc, &c->time_base, ost->st, &pkt);
} else {
AVPacket pkt = { 0 };
av_init_packet(&pkt);
/* encode the image */
ret = avcodec_encode_video2(c, &pkt, frame, &got_packet);
if (ret < 0) {
fprintf(stderr, "Error encoding video frame: %s\n", av_err2str(ret));
exit(1);
}
if (got_packet) {
ret = write_frame(oc, &c->time_base, ost->st, &pkt);
} else {
ret = 0;
}
ret = 0;
}
if (ret < 0) {

View File

@ -116,15 +116,6 @@ fail:
static mfxStatus frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp)
{
DecodeContext *decode = pthis;
if (decode->surfaces)
vaDestroySurfaces(decode->va_dpy, decode->surfaces, decode->nb_surfaces);
av_freep(&decode->surfaces);
av_freep(&decode->surface_ids);
av_freep(&decode->surface_used);
decode->nb_surfaces = 0;
return MFX_ERR_NONE;
}
@ -144,6 +135,16 @@ static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
return MFX_ERR_NONE;
}
static void free_surfaces(DecodeContext *decode)
{
if (decode->surfaces)
vaDestroySurfaces(decode->va_dpy, decode->surfaces, decode->nb_surfaces);
av_freep(&decode->surfaces);
av_freep(&decode->surface_ids);
av_freep(&decode->surface_used);
decode->nb_surfaces = 0;
}
static void free_buffer(void *opaque, uint8_t *data)
{
int *used = opaque;
@ -467,6 +468,12 @@ finish:
av_frame_free(&frame);
if (decoder_ctx)
av_freep(&decoder_ctx->hwaccel_context);
avcodec_free_context(&decoder_ctx);
free_surfaces(&decode);
if (decode.mfx_session)
MFXClose(decode.mfx_session);
if (decode.va_dpy)
@ -474,10 +481,6 @@ finish:
if (dpy)
XCloseDisplay(dpy);
if (decoder_ctx)
av_freep(&decoder_ctx->hwaccel_context);
avcodec_free_context(&decoder_ctx);
avio_close(output_ctx);
return ret;

View File

@ -143,7 +143,7 @@ int main(int argc, char **argv)
fprintf(stderr, "Error muxing packet\n");
break;
}
av_free_packet(&pkt);
av_packet_unref(&pkt);
}
av_write_trailer(ofmt_ctx);

View File

@ -332,7 +332,7 @@ static int decode_audio_frame(AVFrame *frame,
data_present, &input_packet)) < 0) {
fprintf(stderr, "Could not decode frame (error '%s')\n",
get_error_text(error));
av_free_packet(&input_packet);
av_packet_unref(&input_packet);
return error;
}
@ -342,7 +342,7 @@ static int decode_audio_frame(AVFrame *frame,
*/
if (*finished && *data_present)
*finished = 0;
av_free_packet(&input_packet);
av_packet_unref(&input_packet);
return 0;
}
@ -571,7 +571,7 @@ static int encode_audio_frame(AVFrame *frame,
frame, data_present)) < 0) {
fprintf(stderr, "Could not encode frame (error '%s')\n",
get_error_text(error));
av_free_packet(&output_packet);
av_packet_unref(&output_packet);
return error;
}
@ -580,11 +580,11 @@ static int encode_audio_frame(AVFrame *frame,
if ((error = av_write_frame(output_format_context, &output_packet)) < 0) {
fprintf(stderr, "Could not write frame (error '%s')\n",
get_error_text(error));
av_free_packet(&output_packet);
av_packet_unref(&output_packet);
return error;
}
av_free_packet(&output_packet);
av_packet_unref(&output_packet);
}
return 0;

View File

@ -31,7 +31,6 @@
#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>
@ -537,7 +536,7 @@ int main(int argc, char **argv)
if (ret < 0)
goto end;
}
av_free_packet(&packet);
av_packet_unref(&packet);
}
/* flush filters and encoders */
@ -561,7 +560,7 @@ int main(int argc, char **argv)
av_write_trailer(ofmt_ctx);
end:
av_free_packet(&packet);
av_packet_unref(&packet);
av_frame_free(&frame);
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
avcodec_close(ifmt_ctx->streams[i]->codec);

View File

@ -147,7 +147,7 @@ exec /usr/bin/pkg-config "$@@"
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}).
(@url{https://ffmpeg.org/bugreports.html}).
@section How do I encode single pictures into movies?
@ -311,18 +311,18 @@ invoking ffmpeg with several @option{-i} options.
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.
@url{https://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
using the @url{https://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.
@url{https://ffmpeg.org/ffmpeg-filters.html#overlay, @code{overlay}} video filter.
@end itemize
@ -333,19 +333,19 @@ 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,
FFmpeg has a @url{https://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,
FFmpeg has a @url{https://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,
FFmpeg has a @url{https://ffmpeg.org/ffmpeg-protocols.html#concat,
@code{concat}} protocol designed specifically for that, with examples in the
documentation.
@ -485,7 +485,7 @@ scaling adjusts the SAR to keep the DAR constant.
If you want to stretch, or “unstretch”, the image, you need to override the
information with the
@url{http://ffmpeg.org/ffmpeg-filters.html#setdar_002c-setsar, @code{setdar or setsar filters}}.
@url{https://ffmpeg.org/ffmpeg-filters.html#setdar_002c-setsar, @code{setdar or setsar filters}}.
Do not forget to examine carefully the original video to check whether the
stretching comes from the image or from the aspect ratio information.
@ -589,7 +589,7 @@ see @file{libavformat/aviobuf.c} in FFmpeg and @file{libmpdemux/demux_lavf.c} in
@section Where is the documentation about ffv1, msmpeg4, asv1, 4xm?
see @url{http://www.ffmpeg.org/~michael/}
see @url{https://www.ffmpeg.org/~michael/}
@section How do I feed H.263-RTP (and other codecs in RTP) to libavcodec?

View File

@ -253,6 +253,10 @@ Overwrite output files without asking.
Do not overwrite output files, and exit immediately if a specified
output file already exists.
@item -stream_loop @var{number} (@emph{input})
Set number of times input stream shall be looped. Loop 0 means no loop,
loop -1 means infinite loop.
@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
@ -293,7 +297,9 @@ see @ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1)
-to and -t are mutually exclusive and -t has priority.
@item -fs @var{limit_size} (@emph{output})
Set the file size limit, expressed in bytes.
Set the file size limit, expressed in bytes. No further chunk of bytes is written
after the limit is exceeded. The size of the output file is slightly more than the
requested file size.
@item -ss @var{position} (@emph{input/output})
When used as an input option (before @code{-i}), seeks in this input file to
@ -335,8 +341,8 @@ see @ref{date syntax,,the Date section in the ffmpeg-utils(1) manual,ffmpeg-util
Set a metadata key/value pair.
An optional @var{metadata_specifier} may be given to set metadata
on streams or chapters. See @code{-map_metadata} documentation for
details.
on streams, chapters or programs. See @code{-map_metadata}
documentation for details.
This option overrides metadata set with @code{-map_metadata}. It is
also possible to delete metadata by using an empty value.
@ -351,6 +357,11 @@ To set the language of the first audio stream:
ffmpeg -i INPUT -metadata:s:a:0 language=eng OUTPUT
@end example
@item -program [title=@var{title}:][program_num=@var{program_num}:]st=@var{stream}[:st=@var{stream}...] (@emph{output})
Creates a program with the specified @var{title}, @var{program_num} and adds the specified
@var{stream}(s) to it.
@item -target @var{type} (@emph{output})
Specify target file type (@code{vcd}, @code{svcd}, @code{dvd}, @code{dv},
@code{dv50}). @var{type} may be prefixed with @code{pal-}, @code{ntsc-} or
@ -671,6 +682,16 @@ Use VDPAU (Video Decode and Presentation API for Unix) hardware acceleration.
@item dxva2
Use DXVA2 (DirectX Video Acceleration) hardware acceleration.
@item qsv
Use the Intel QuickSync Video acceleration for video transcoding.
Unlike most other values, this option does not enable accelerated decoding (that
is used automatically whenever a qsv decoder is selected), but accelerated
transcoding, without copying the frames into the system memory.
For it to work, both the decoder and the encoder must support QSV acceleration
and no filters must be used.
@end table
This option has no effect if the selected hwaccel is not available or not
@ -697,6 +718,20 @@ is not specified, the value of the @var{DISPLAY} environment variable is used
@item dxva2
For DXVA2, this option should contain the number of the display adapter to use.
If this option is not specified, the default adapter is used.
@item qsv
For QSV, this option corresponds to the valus of MFX_IMPL_* . Allowed values
are:
@table @option
@item auto
@item sw
@item hw
@item auto_any
@item hw_any
@item hw2
@item hw3
@item hw4
@end table
@end table
@item -hwaccels
@ -1233,6 +1268,14 @@ Discard all frames excepts keyframes.
Discard all frames.
@end table
@item -abort_on @var{flags} (@emph{global})
Stop and abort on various conditions. The following flags are available:
@table @option
@item empty_output
No packets were passed to the muxer, the output is empty.
@end table
@item -xerror (@emph{global})
Stop and exit on error

View File

@ -197,6 +197,15 @@ Toggle full screen.
@item p, SPC
Pause.
@item m
Toggle mute.
@item 9, 0
Decrease and increase volume respectively.
@item /, *
Decrease and increase volume respectively.
@item a
Cycle audio channel in the current program.
@ -229,9 +238,12 @@ Seek to the previous/next chapter.
or if there are no chapters
Seek backward/forward 10 minutes.
@item mouse click
@item right mouse click
Seek to percentage in file corresponding to fraction of width.
@item left mouse double-click
Toggle full screen.
@end table
@c man end

View File

@ -232,7 +232,8 @@ Frame scheduling
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 request_frame could produce a frame, or at least make progress
towards producing 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.
@ -244,20 +245,18 @@ Frame scheduling
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;
}
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.
the filter_frame method possibly will be called and do the work.
Legacy API
==========

File diff suppressed because it is too large Load Diff

View File

@ -53,14 +53,6 @@ instructions for installing the libraries.
Then pass @code{--enable-libopencore-amrnb} and/or
@code{--enable-libopencore-amrwb} to configure to enable them.
@subsection VisualOn AAC encoder library
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.
Then pass @code{--enable-libvo-aacenc} to configure to enable it.
@subsection VisualOn AMR-WB encoder library
FFmpeg can make use of the VisualOn AMR-WBenc library for AMR-WB encoding.
@ -173,12 +165,6 @@ Go to @url{http://sourceforge.net/projects/zapping/} and follow the instructions
installing the library. Then pass @code{--enable-libzvbi} to configure to
enable it.
@float NOTE
libzvbi is licensed under the GNU General Public License Version 2 or later
(see @url{http://www.gnu.org/licenses/old-licenses/gpl-2.0.html} for details),
you must upgrade FFmpeg's license to GPL in order to use it.
@end float
@section AviSynth
FFmpeg can read AviSynth scripts as input. To enable support, pass
@ -223,6 +209,7 @@ library:
@multitable @columnfractions .4 .1 .1 .4
@item Name @tab Encoding @tab Decoding @tab Comments
@item 3dostr @tab @tab X
@item 4xm @tab @tab X
@tab 4X Technologies format, used in some games.
@item 8088flex TMV @tab @tab X
@ -241,10 +228,14 @@ library:
@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 Interplay ACM @tab @tab X
@tab Audio only format used in some Interplay games.
@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 ADS/SS2 @tab @tab X
@tab Audio format used on the PS2.
@item APNG @tab X @tab X
@item ASF @tab X @tab X
@item AST @tab X @tab X
@ -285,6 +276,7 @@ library:
@item CD+G @tab @tab X
@tab Video format used by CD+G karaoke disks
@item Phantom Cine @tab @tab X
@item Cineform HD @tab @tab X
@item Commodore CDXL @tab @tab X
@tab Amiga CD video format
@item Core Audio Format @tab X @tab X
@ -296,6 +288,7 @@ library:
@tab Audio format used in some games by CRYO Interactive Entertainment.
@item D-Cinema audio @tab X @tab X
@item Deluxe Paint Animation @tab @tab X
@item DCSTR @tab @tab X
@item DFA @tab @tab X
@tab This format is used in Chronomaster game
@item DirectDraw Surface @tab @tab X
@ -322,6 +315,8 @@ library:
@item G.723.1 @tab X @tab X
@item G.729 BIT @tab X @tab X
@item G.729 raw @tab @tab X
@item GENH @tab @tab X
@tab Audio format for various games.
@item GIF Animation @tab X @tab X
@item GXF @tab X @tab X
@tab General eXchange Format SMPTE 360M, used by Thomson Grass Valley
@ -344,6 +339,7 @@ library:
@tab A format generated by IndigoVision 8000 video server.
@item IVF (On2) @tab X @tab X
@tab A format used by libvpx
@item Internet Video Recording @tab @tab X
@item IRCAM @tab X @tab X
@item LATM @tab X @tab X
@item LMLM4 @tab @tab X
@ -380,6 +376,8 @@ library:
@tab also known as DVB Transport Stream
@item MPEG-4 @tab X @tab X
@tab MPEG-4 is a variant of QuickTime.
@item MSF @tab @tab X
@tab Audio format used on the PS3.
@item Mirillis FIC video @tab @tab X
@tab No cursor rendering.
@item MIME multipart JPEG @tab X @tab
@ -463,6 +461,7 @@ library:
@item Redirector @tab @tab X
@item RedSpark @tab @tab X
@item Renderware TeXture Dictionary @tab @tab X
@item Resolume DXV @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
@ -495,6 +494,8 @@ library:
@item SoX native format @tab X @tab X
@item SUN AU format @tab X @tab X
@item SUP raw PGS subtitles @tab @tab X
@item SVAG @tab @tab X
@tab Audio format used in Konami PS2 games.
@item TDSC @tab @tab X
@item Text files @tab @tab X
@item THP @tab @tab X
@ -502,9 +503,13 @@ library:
@item Tiertex Limited SEQ @tab @tab X
@tab Tiertex .seq files used in the DOS CD-ROM version of the game Flashback.
@item True Audio @tab @tab X
@item VAG @tab @tab X
@tab Audio format used in many Sony PS2 games.
@item VC-1 test bitstream @tab X @tab X
@item Vidvox Hap @tab X @tab X
@item Vivo @tab @tab X
@item VPK @tab @tab X
@tab Audio format used in Sony PS games.
@item WAV @tab X @tab X
@item WavPack @tab X @tab X
@item WebM @tab X @tab X
@ -515,8 +520,11 @@ library:
@tab Multimedia format used in Westwood Studios games.
@item Westwood Studios VQA @tab @tab X
@tab Multimedia format used in Westwood Studios games.
@item WVE @tab @tab X
@item XMV @tab @tab X
@tab Microsoft video container used in Xbox games.
@item XVAG @tab @tab X
@tab Audio format used on the PS3.
@item xWMA @tab @tab X
@tab Microsoft audio container used by XAudio 2.
@item eXtended BINary text (XBIN) @tab @tab X
@ -799,6 +807,7 @@ 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 Screenpresso @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
@ -865,12 +874,13 @@ following image formats are supported:
@item Name @tab Encoding @tab Decoding @tab Comments
@item 8SVX exponential @tab @tab X
@item 8SVX fibonacci @tab @tab X
@item AAC @tab EX @tab X
@tab encoding supported through internal encoder and external libraries libfaac and libfdk-aac
@item AAC+ @tab E @tab IX
@tab encoding supported through external library libaacplus
@item AAC @tab E @tab X
@tab encoding supported through external library libfaac and libvo-aacenc
@tab encoding supported through external library libfdk-aac
@item AC-3 @tab IX @tab IX
@item ADPCM 4X Movie @tab @tab X
@item APDCM Yamaha AICA @tab @tab X
@item ADPCM CDROM XA @tab @tab X
@item ADPCM Creative Technology @tab @tab X
@tab 16 -> 4, 8 -> 4, 8 -> 3, 8 -> 2
@ -906,6 +916,7 @@ following image formats are supported:
@item ADPCM Nintendo Gamecube AFC @tab @tab X
@item ADPCM Nintendo Gamecube DTK @tab @tab X
@item ADPCM Nintendo THP @tab @tab X
@item APDCM Playstation @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.
@ -913,7 +924,7 @@ following image formats are supported:
@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
@item ADPCM VIMA
@item ADPCM VIMA @tab @tab X
@tab Used in LucasArts SMUSH animations.
@item ADPCM Westwood Studios IMA @tab @tab X
@tab Used in Westwood Studios games like Command and Conquer.
@ -944,6 +955,8 @@ following image formats are supported:
@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 Squareroot-Delta-Exact @tab @tab X
@tab Used in various games.
@item DPCM Sierra Online @tab @tab X
@tab Used in Sierra Online game audio files.
@item DPCM Sol @tab @tab X
@ -958,7 +971,7 @@ following image formats are supported:
@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 X @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
@ -968,6 +981,7 @@ following image formats are supported:
@item iLBC (Internet Low Bitrate Codec) @tab E @tab E
@tab encoding and decoding supported through external library libilbc
@item IMC (Intel Music Coder) @tab @tab X
@item Interplay ACM @tab @tab X
@item MACE (Macintosh Audio Compression/Expansion) 3:1 @tab @tab X
@item MACE (Macintosh Audio Compression/Expansion) 6:1 @tab @tab X
@item MLP (Meridian Lossless Packing) @tab @tab X
@ -1052,6 +1066,8 @@ following image formats are supported:
@item Windows Media Audio Lossless @tab @tab X
@item Windows Media Audio Pro @tab @tab X
@item Windows Media Audio Voice @tab @tab X
@item Xbox Media Audio 1 @tab @tab X
@item Xbox Media Audio 2 @tab @tab X
@end multitable
@code{X} means that encoding (resp. decoding) is supported.

View File

@ -65,6 +65,21 @@ git clone git@@source.ffmpeg.org:ffmpeg <target>
This will put the FFmpeg sources into the directory @var{<target>} and let
you push back your changes to the remote repository.
@example
git clone gil@@ffmpeg.org:ffmpeg-web <target>
@end example
This will put the source of the FFmpeg website into the directory
@var{<target>} and let you push back your changes to the remote repository.
(Note that @var{gil} stands for GItoLite and is not a typo of @var{git}.)
If you don't have write-access to the ffmpeg-web repository, you can
create patches after making a read-only ffmpeg-web clone:
@example
git clone git://ffmpeg.org/ffmpeg-web <target>
@end example
Make sure that you do not have Windows line endings in your checkouts,
otherwise you may experience spurious compilation failures. One way to
achieve this is to run

View File

@ -121,7 +121,7 @@ Specify the audio device by its index. Overrides anything given in the input fil
@item -pixel_format <FORMAT>
Request the video device to use a specific pixel format.
If the specified format is not supported, a list of available formats is given
und the first one in this list is used instead. Available pixel formats are:
and the first one in this list is used instead. Available pixel formats are:
@code{monob, rgb555be, rgb555le, rgb565be, rgb565le, rgb24, bgr24, 0rgb, bgr0, 0bgr, rgb0,
bgr48be, uyvy422, yuva444p, yuva444p16le, yuv444p, yuv422p16, yuv422p10, yuv444p10,
yuv420p, nv12, yuyv422, gray}
@ -218,7 +218,8 @@ On Windows, you need to run the IDL files through @command{widl}.
DeckLink is very picky about the formats it supports. Pixel format is
uyvy422 or v210, framerate and video size must be determined for your device with
@command{-list_formats 1}. Audio sample rate is always 48 kHz and the number
of channels can be 2, 8 or 16.
of channels can be 2, 8 or 16. Note that all audio channels are bundled in one single
audio track.
@subsection Options
@ -236,6 +237,20 @@ Defaults to @option{false}.
If set to @samp{1}, video is captured in 10 bit v210 instead
of uyvy422. Not all Blackmagic devices support this option.
@item teletext_lines
If set to nonzero, an additional teletext stream will be captured from the
vertical ancillary data. This option is a bitmask of the VBI lines checked,
specifically lines 6 to 22, and lines 318 to 335. Line 6 is the LSB in the mask.
Selected lines which do not contain teletext information will be ignored. You
can use the special @option{all} constant to select all possible lines, or
@option{standard} to skip lines 6, 318 and 319, which are not compatible with all
receivers. Capturing teletext only works for SD PAL sources in 8 bit mode.
To use this option, ffmpeg needs to be compiled with @code{--enable-libzvbi}.
@item channels
Defines number of audio channels to capture. Must be @samp{2}, @samp{8} or @samp{16}.
Defaults to @samp{2}.
@end table
@subsection Examples
@ -266,6 +281,12 @@ Capture video clip at 1080i50 10 bit:
ffmpeg -bm_v210 1 -f decklink -i 'UltraStudio Mini Recorder@@11' -acodec copy -vcodec copy output.avi
@end example
@item
Capture video clip at 1080i50 with 16 audio channels:
@example
ffmpeg -channels 16 -f decklink -i 'UltraStudio Mini Recorder@@11' -acodec copy -vcodec copy output.avi
@end example
@end itemize
@section dshow
@ -1352,17 +1373,13 @@ Set the video frame size. Default value is @code{vga}.
Use the MIT-SHM extension for shared memory. Default value is @code{1}.
It may be necessary to disable it for remote displays (legacy x11grab
only).
@item grab_x
@item grab_y
Set the grabbing region coordinates. They are expressed as offset from
the top left corner of the X11 window and correspond to the
@var{x_offset} and @var{y_offset} parameters in the device name. The
default value for both options is 0.
@end table
@subsection @var{grab_x} @var{grab_y} AVOption
The syntax is:
@example
-grab_x @var{x_offset} -grab_y @var{y_offset}
@end example
Set the grabbing region coordinates. They are expressed as offset from the top left
corner of the X11 window. The default value is 0.
@c man end INPUT DEVICES

View File

@ -1,8 +1,6 @@
FFmpeg's bug/feature request tracker manual
=================================================
NOTE: This is a draft.
Overview:
---------
@ -22,9 +20,9 @@ a mail for every change to every issue.
(the above does all work already after light testing)
The subscription URL for the ffmpeg-trac list is:
http(s)://lists.ffmpeg.org/mailman/listinfo/ffmpeg-trac
https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-trac
The URL of the webinterface of the tracker is:
http(s)://trac.ffmpeg.org
https://trac.ffmpeg.org
Type:
-----
@ -42,12 +40,16 @@ feature request / enhancement
where the current implementation cannot be considered wrong.
license violation
ticket to keep track of (L)GPL violations of ffmpeg by others
Ticket to keep track of (L)GPL violations of ffmpeg by others.
sponsoring request
Developer requests for hardware, software, specifications, money,
refunds, etc.
task
A task/reminder such as setting up a FATE client, adding filters to
Trac, etc.
Priority:
---------
critical
@ -66,7 +68,8 @@ important
don't exist in a past revision or another branch.
normal
Default setting. Use this if the bug does not match the other
priorities or if you are unsure of what priority to choose.
minor
Bugs about things like spelling errors, "mp2" instead of
@ -163,14 +166,23 @@ Component:
avcodec
issues in libavcodec/*
avdevice
issues in libavdevice/*
avfilter
issues in libavfilter/*
avformat
issues in libavformat/*
avutil
issues in libavutil/*
regression test
issues in tests/*
build system
issues in or related to configure/Makefile
documentation
issues in or related to doc/*
ffmpeg
issues in or related to ffmpeg.c
@ -184,11 +196,23 @@ ffprobe
ffserver
issues in or related to ffserver.c
build system
issues in or related to configure/Makefile
postproc
issues in libpostproc/*
regression
bugs which were not present in a past revision
swresample
issues in libswresample/*
swscale
issues in libswscale/*
trac
issues related to our issue tracker
undetermined
default component; choose this if unsure
website
issues related to the website
wiki
issues related to the wiki

View File

@ -37,6 +37,61 @@ ID3v2.3 and ID3v2.4) are supported. The default is version 4.
@end table
@anchor{asf}
@section asf
Advanced Systems Format muxer.
Note that Windows Media Audio (wma) and Windows Media Video (wmv) use this
muxer too.
@subsection Options
It accepts the following options:
@table @option
@item packet_size
Set the muxer packet size. By tuning this setting you may reduce data
fragmentation or muxer overhead depending on your source. Default value is
3200, minimum is 100, maximum is 64k.
@end table
@anchor{chromaprint}
@section chromaprint
Chromaprint fingerprinter
This muxer feeds audio data to the Chromaprint library, which generates
a fingerprint for the provided audio data. It takes a single signed
native-endian 16-bit raw audio stream.
@subsection Options
@table @option
@item silence_threshold
Threshold for detecting silence, ranges from 0 to 32767. -1 for default
(required for use with the AcoustID service).
@item algorithm
Algorithm index to fingerprint with.
@item fp_format
Format to output the fingerprint as. Accepts the following options:
@table @samp
@item raw
Binary raw fingerprint
@item compressed
Binary compressed fingerprint
@item base64
Base64 compressed fingerprint
@end table
@end table
@anchor{crc}
@section crc
@ -549,7 +604,7 @@ 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.
hash. Timestamps are ignored.
The output of the muxer consists of a single line of the form:
MD5=@var{MD5}, where @var{MD5} is a hexadecimal number representing
@ -823,6 +878,8 @@ Reemit PAT/PMT before writing the next packet.
Use LATM packetization for AAC.
@item pat_pmt_at_frames
Reemit PAT and PMT at each video frame.
@item system_b
Conform to System B (DVB) instead of System A (ATSC).
@end table
@subsection Example
@ -1063,6 +1120,28 @@ to create files at 12:00 o'clock, 12:15, 12:30, etc.
Default value is "0".
@item segment_clocktime_offset @var{duration}
Delay the segment splitting times with the specified duration when using
@option{segment_atclocktime}.
For example with @option{segment_time} set to "900" and
@option{segment_clocktime_offset} set to "300" this makes it possible to
create files at 12:05, 12:20, 12:35, etc.
Default value is "0".
@item segment_clocktime_wrap_duration @var{duration}
Force the segmenter to only start a new segment if a packet reaches the muxer
within the specified duration after the segmenting clock time. This way you
can make the segmenter more resilient to backward local time jumps, such as
leap seconds or transition to standard time from daylight savings time.
Assuming that the delay between the packets of your source is less than 0.5
second you can detect a leap second by specifying 0.5 as the duration.
Default is the maximum possible duration which means starting a new segment
regardless of the elapsed time since the last clock time.
@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".
@ -1252,7 +1331,8 @@ Several bitstream filters can be specified, separated by ",".
@item select
Select the streams that should be mapped to the slave output,
specified by a stream specifier. If not specified, this defaults to
all the input streams.
all the input streams. You may use multiple stream specifiers
separated by commas (@code{,}) e.g.: @code{a:0,v}
@end table
@subsection Examples

View File

@ -107,8 +107,13 @@ Notes:
@itemize
@item Building natively using MSYS2 can be sped up by disabling implicit rules
in the Makefile by calling @code{make -r} instead of plain @code{make}. This
@item Building for the MSYS environment is discouraged, MSYS2 provides a full
MinGW-w64 environment through @file{mingw64_shell.bat} or
@file{mingw32_shell.bat} that should be used instead of the environment
provided by @file{msys2_shell.bat}.
@item Building using MSYS2 can be sped up by disabling implicit rules in the
Makefile by calling @code{make -r} instead of plain @code{make}. This
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}).
@ -122,6 +127,25 @@ libavformat) as DLLs.
@end itemize
@subsection Native Windows compilation using MSYS2
The MSYS2 MinGW-w64 environment provides ready to use toolchains and dependencies
through @command{pacman}.
Make sure to use @file{mingw64_shell.bat} or @file{mingw32_shell.bat} to have
the correct MinGW-w64 environment. The default install provides shortcuts to
them under @command{MinGW-w64 Win64 Shell} and @command{MinGW-w64 Win32 Shell}.
@example
# normal msys2 packages
pacman -S make pkgconf diffutils
# mingw-w64 packages and toolchains
pacman -S mingw-w64-x86_64-yasm mingw-w64-x86_64-gcc mingw-w64-x86_64-SDL
@end example
To target 32bit replace the @code{x86_64} with @code{i686} in the command above.
@section Microsoft Visual C++ or Intel C++ Compiler for Windows
FFmpeg can be built with MSVC 2012 or earlier using a C99-to-C89 conversion utility
@ -290,7 +314,7 @@ These library packages are only available from
@uref{http://sourceware.org/cygwinports/, Cygwin Ports}:
@example
yasm, libSDL-devel, libfaac-devel, libaacplus-devel, libgsm-devel, libmp3lame-devel,
yasm, libSDL-devel, libfaac-devel, libgsm-devel, libmp3lame-devel,
libschroedinger1.0-devel, speex-devel, libtheora-devel, libxvidcore-devel
@end example

View File

@ -1,3 +1,22 @@
@chapter Protocol Options
@c man begin PROTOCOL OPTIONS
The libavformat library provides some generic global options, which
can be set on all the protocols. In addition each protocol may support
so-called private options, which are specific for that component.
The list of supported options follows:
@table @option
@item protocol_whitelist @var{list} (@emph{input})
Set a ","-separated list of allowed protocols. "ALL" matches all protocols. Protocols
prefixed by "-" are disabled.
All protocols are allowed by default but protocols used by an another
protocol (nested protocols) are restricted to a per protocol subset.
@end table
@c man end PROTOCOL OPTIONS
@chapter Protocols
@c man begin PROTOCOLS
@ -240,6 +259,9 @@ If set to 1 use chunked Transfer-Encoding for posts, default is 1.
@item content_type
Set a specific content type for the POST messages.
@item http_proxy
set HTTP proxy to tunnel through e.g. http://example.com:1234
@item headers
Set custom HTTP headers, can override built in default headers. The
value must be a string encoding the headers.
@ -260,6 +282,16 @@ Set timeout in microseconds of socket I/O operations used by the underlying low
operation. By default it is set to -1, which means that the timeout is
not specified.
@item reconnect_at_eof
If set then eof is treated like an error and causes reconnection, this is useful
for live / endless streams.
@item reconnect_streamed
If set then even streamed/non seekable streams will be reconnected on errors.
@item reconnect_delay_max
Sets the maximum delay in seconds after which to give up reconnecting
@item mime_type
Export the MIME type.
@ -1134,6 +1166,12 @@ than this time interval, raise error.
@item listen_timeout=@var{milliseconds}
Set listen timeout, expressed in milliseconds.
@item recv_buffer_size=@var{bytes}
Set receive buffer size, expressed bytes.
@item send_buffer_size=@var{bytes}
Set send buffer size, expressed bytes.
@end table
The following example shows how to setup a listening TCP connection

View File

@ -66,8 +66,8 @@ Set rematrix volume. Default value is 1.0.
@item rematrix_maxval
Set maximum output value for rematrixing.
This can be used to prevent clipping vs. preventing volumn reduction
A value of 1.0 prevents cliping.
This can be used to prevent clipping vs. preventing volume reduction.
A value of 1.0 prevents clipping.
@item flags, swr_flags
Set flags used by the converter. Default value is 0.
@ -94,13 +94,13 @@ select triangular dither
@item triangular_hp
select triangular dither with high pass
@item lipshitz
select lipshitz noise shaping dither
select Lipshitz noise shaping dither.
@item shibata
select shibata noise shaping dither
select Shibata noise shaping dither.
@item low_shibata
select low shibata noise shaping dither
select low Shibata noise shaping dither.
@item high_shibata
select high shibata noise shaping dither
select high Shibata noise shaping dither.
@item f_weighted
select f-weighted noise shaping dither
@item modified_e_weighted
@ -132,7 +132,7 @@ 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.
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
@ -214,13 +214,13 @@ It accepts the following values:
@item cubic
select cubic
@item blackman_nuttall
select Blackman Nuttall Windowed Sinc
select Blackman Nuttall windowed sinc
@item kaiser
select Kaiser Windowed Sinc
select Kaiser windowed sinc
@end table
@item kaiser_beta
For swr only, set Kaiser Window Beta value. Must be an integer in the
For swr only, set Kaiser window beta value. Must be a double float value in the
interval [2,16], default value is 9.
@item output_sample_bits

View File

@ -46,7 +46,7 @@ Select Gaussian rescaling algorithm.
Select sinc rescaling algorithm.
@item lanczos
Select lanczos rescaling algorithm.
Select Lanczos rescaling algorithm.
@item spline
Select natural bicubic spline rescaling algorithm.
@ -91,6 +91,7 @@ Select source range.
@item dst_range
Select destination range.
@anchor{sws_params}
@item param0, param1
Set scaling algorithm parameters. The specified values are specific of
some scaling algorithms and ignored by others. The specified values

View File

@ -3,8 +3,8 @@ libavfilter.
Foreword: just like everything else in FFmpeg, libavfilter is monolithic, which
means that it is highly recommended that you submit your filters to the FFmpeg
development mailing-list and make sure it is applied. Otherwise, your filter is
likely to have a very short lifetime due to more a less regular internal API
development mailing-list and make sure that they are applied. Otherwise, your filters
are likely to have a very short lifetime due to more or less regular internal API
changes, and a limited distribution, review, and testing.
Bootstrap
@ -64,7 +64,7 @@ filter, so you can update the boilerplate with your credits.
Doxy
----
Next chunk is the Doxygen about the file. See http://ffmpeg.org/doxygen/trunk/.
Next chunk is the Doxygen about the file. See https://ffmpeg.org/doxygen/trunk/.
Detail here what the filter is, does, and add some references if you feel like
it.
@ -73,11 +73,11 @@ Context
Skip the headers and scroll down to the definition of FoobarContext. This is
your local state context. It is already filled with 0 when you get it so do not
worry about uninitialized read into this context. This is where you put every
"global" information you need, typically the variable storing the user options.
worry about uninitialized reads into this context. This is where you put all
"global" information that you need; typically the variables storing the user options.
You'll notice the first field "const AVClass *class"; it's the only field you
need to keep assuming you have a context. There are some magic you don't care
about around this field, just let it be (in first position) for now.
need to keep assuming you have a context. There is some magic you don't need to
care about around this field, just let it be (in the first position) for now.
Options
-------
@ -87,7 +87,7 @@ options. For example, -vf foobar=mode=colormix:high=0.4:low=0.1. Most options
have the following pattern:
name, description, offset, type, default value, minimum value, maximum value, flags
- name is the option name, keep it simple, lowercase
- name is the option name, keep it simple and lowercase
- description are short, in lowercase, without period, and describe what they
do, for example "set the foo of the bar"
- offset is the offset of the field in your local context, see the OFFSET()
@ -99,7 +99,7 @@ have the following pattern:
- min and max values define the range of available values, inclusive
- flags are AVOption generic flags. See AV_OPT_FLAG_* definitions
In doubt, just look at the other AVOption definitions all around the codebase,
When in doubt, just look at the other AVOption definitions all around the codebase,
there are tons of examples.
Class
@ -146,14 +146,14 @@ we won't cover this here since vf_foobar is just a simple 1:1 filter.
uninit()
~~~~~~~~
Similarly, there is the uninit() callback, doing what the name suggest. Free
Similarly, there is the uninit() callback, doing what the name suggests. Free
everything you allocated here.
query_formats()
~~~~~~~~~~~~~~~
This is following the init() and is used for the format negotiation, basically
where you say what pixel format(s) (gray, rgb 32, yuv 4:2:0, ...) you accept
This follows the init() and is used for the format negotiation. Basically
you specify here what pixel format(s) (gray, rgb 32, yuv 4:2:0, ...) you accept
for your inputs, and what you can output. All pixel formats are defined in
libavutil/pixfmt.h. If you don't change the pixel format between the input and
the output, you just have to define a pixel formats array and call
@ -182,7 +182,7 @@ will update outlink->w and outlink->h.
filter_frame()
~~~~~~~~~~~~~~
This is the callback you are waiting from the beginning: it is where you
This is the callback you are waiting for from the beginning: it is where you
process the received frames. Along with the frame, you get the input link from
where the frame comes from.
@ -317,7 +317,7 @@ Adding timeline support
feature to add. In the most simple case, you just have to add
AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC to the AVFilter.flags. You can typically
do this when your filter does not need to save the previous context frames, or
basically if your filter just alter whatever goes in and doesn't need
basically if your filter just alters whatever goes in and doesn't need
previous/future information. See for instance commit 86cb986ce that adds
timeline support to the fieldorder filter.

424
ffmpeg.c
View File

@ -32,14 +32,12 @@
#include <limits.h>
#include <stdint.h>
#if HAVE_ISATTY
#if HAVE_IO_H
#include <io.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#endif
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
@ -64,7 +62,6 @@
#include "libavcodec/mathops.h"
#include "libavformat/os_support.h"
# include "libavfilter/avcodec.h"
# include "libavfilter/avfilter.h"
# include "libavfilter/buffersrc.h"
# include "libavfilter/buffersink.h"
@ -371,11 +368,7 @@ 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) {
if (tcgetattr (0, &tty) == 0) {
oldtty = tty;
restore_tty = 1;
@ -534,6 +527,8 @@ static void ffmpeg_cleanup(int ret)
av_freep(&ost->audio_channels_map);
ost->audio_channels_mapped = 0;
av_dict_free(&ost->sws_dict);
avcodec_free_context(&ost->enc_ctx);
av_freep(&output_streams[i]);
@ -561,8 +556,12 @@ static void ffmpeg_cleanup(int ret)
av_freep(&input_streams[i]);
}
if (vstats_file)
fclose(vstats_file);
if (vstats_file) {
if (fclose(vstats_file))
av_log(NULL, AV_LOG_ERROR,
"Error closing vstats file, loss of information possible: %s\n",
av_err2str(AVERROR(errno)));
}
av_freep(&vstats_filename);
av_freep(&input_streams);
@ -660,7 +659,7 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
*/
if (!(avctx->codec_type == AVMEDIA_TYPE_VIDEO && avctx->codec)) {
if (ost->frame_number >= ost->max_frames) {
av_free_packet(pkt);
av_packet_unref(pkt);
return;
}
ost->frame_number++;
@ -678,58 +677,22 @@ static void write_frame(AVFormatContext *s, AVPacket *pkt, OutputStream *ost)
else
ost->error[i] = -1;
}
if (ost->frame_rate.num && ost->is_cfr) {
if (pkt->duration > 0)
av_log(NULL, AV_LOG_WARNING, "Overriding packet duration by frame rate, this should not happen\n");
pkt->duration = av_rescale_q(1, av_inv_q(ost->frame_rate),
ost->st->time_base);
}
}
if (bsfc)
av_packet_split_side_data(pkt);
while (bsfc) {
AVPacket new_pkt = *pkt;
AVDictionaryEntry *bsf_arg = av_dict_get(ost->bsf_args,
bsfc->filter->name,
NULL, 0);
int a = av_bitstream_filter_filter(bsfc, avctx,
bsf_arg ? bsf_arg->value : NULL,
&new_pkt.data, &new_pkt.size,
pkt->data, pkt->size,
pkt->flags & AV_PKT_FLAG_KEY);
FF_DISABLE_DEPRECATION_WARNINGS
if(a == 0 && new_pkt.data != pkt->data
#if FF_API_DESTRUCT_PACKET
&& new_pkt.destruct
#endif
) {
FF_ENABLE_DEPRECATION_WARNINGS
uint8_t *t = av_malloc(new_pkt.size + AV_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, AV_INPUT_BUFFER_PADDING_SIZE);
new_pkt.data = t;
new_pkt.buf = NULL;
a = 1;
} else
a = AVERROR(ENOMEM);
}
if (a > 0) {
pkt->side_data = NULL;
pkt->side_data_elems = 0;
av_free_packet(pkt);
new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size,
av_buffer_default_free, NULL, 0);
if (!new_pkt.buf)
exit_program(1);
} else if (a < 0) {
new_pkt = *pkt;
av_log(NULL, AV_LOG_ERROR, "Failed to open bitstream filter %s for stream %d with codec %s",
bsfc->filter->name, pkt->stream_index,
avctx->codec ? avctx->codec->name : "copy");
print_error("", a);
if (exit_on_error)
exit_program(1);
}
*pkt = new_pkt;
bsfc = bsfc->next;
if ((ret = av_apply_bitstream_filters(avctx, pkt, bsfc)) < 0) {
print_error("", ret);
if (exit_on_error)
exit_program(1);
}
if (!(s->oformat->flags & AVFMT_NOTIMESTAMPS)) {
@ -790,7 +753,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
main_return_code = 1;
close_all_output_streams(ost, MUXER_FINISHED | ENCODER_FINISHED, ENCODER_FINISHED);
}
av_free_packet(pkt);
av_packet_unref(pkt);
}
static void close_output_stream(OutputStream *ost)
@ -990,11 +953,11 @@ static void do_video_out(AVFormatContext *s,
ost->last_nb0_frames[1],
ost->last_nb0_frames[2]);
} else {
delta0 = sync_ipts - ost->sync_opts;
delta0 = sync_ipts - ost->sync_opts; // delta0 is the "drift" between the input frame (next_picture) and where it would fall in the output.
delta = delta0 + duration;
/* by default, we output a single frame */
nb0_frames = 0;
nb0_frames = 0; // tracks the number of times the PREVIOUS frame should be duplicated, mostly for variable framerate (VFR)
nb_frames = 1;
format_video_sync = video_sync_method;
@ -1013,25 +976,25 @@ static void do_video_out(AVFormatContext *s,
format_video_sync = VSYNC_VSCFR;
}
}
ost->is_cfr = (format_video_sync == VSYNC_CFR || format_video_sync == VSYNC_VSCFR);
if (delta0 < 0 &&
delta > 0 &&
format_video_sync != VSYNC_PASSTHROUGH &&
format_video_sync != VSYNC_DROP) {
double cor = FFMIN(-delta0, duration);
if (delta0 < -0.6) {
av_log(NULL, AV_LOG_WARNING, "Past duration %f too large\n", -delta0);
} else
av_log(NULL, AV_LOG_DEBUG, "Cliping frame in rate conversion by %f\n", -delta0);
sync_ipts += cor;
duration -= cor;
delta0 += cor;
av_log(NULL, AV_LOG_DEBUG, "Clipping frame in rate conversion by %f\n", -delta0);
sync_ipts = ost->sync_opts;
duration += delta0;
delta0 = 0;
}
switch (format_video_sync) {
case VSYNC_VSCFR:
if (ost->frame_number == 0 && delta - duration >= 0.5) {
av_log(NULL, AV_LOG_DEBUG, "Not duplicating %d initial frames\n", (int)lrintf(delta - duration));
if (ost->frame_number == 0 && delta0 >= 0.5) {
av_log(NULL, AV_LOG_DEBUG, "Not duplicating %d initial frames\n", (int)lrintf(delta0));
delta = duration;
delta0 = 0;
ost->sync_opts = lrint(sync_ipts);
@ -1071,22 +1034,22 @@ static void do_video_out(AVFormatContext *s,
sizeof(ost->last_nb0_frames[0]) * (FF_ARRAY_ELEMS(ost->last_nb0_frames) - 1));
ost->last_nb0_frames[0] = nb0_frames;
if (nb0_frames == 0 && ost->last_droped) {
if (nb0_frames == 0 && ost->last_dropped) {
nb_frames_drop++;
av_log(NULL, AV_LOG_VERBOSE,
"*** dropping frame %d from stream %d at ts %"PRId64"\n",
ost->frame_number, ost->st->index, ost->last_frame->pts);
}
if (nb_frames > (nb0_frames && ost->last_droped) + (nb_frames > nb0_frames)) {
if (nb_frames > (nb0_frames && ost->last_dropped) + (nb_frames > nb0_frames)) {
if (nb_frames > dts_error_threshold * 30) {
av_log(NULL, AV_LOG_ERROR, "%d frame duplication too large, skipping\n", nb_frames - 1);
nb_frames_drop++;
return;
}
nb_frames_dup += nb_frames - (nb0_frames && ost->last_droped) - (nb_frames > nb0_frames);
nb_frames_dup += nb_frames - (nb0_frames && ost->last_dropped) - (nb_frames > nb0_frames);
av_log(NULL, AV_LOG_VERBOSE, "*** %d dup!\n", nb_frames - 1);
}
ost->last_droped = nb_frames == nb0_frames && next_picture;
ost->last_dropped = nb_frames == nb0_frames && next_picture;
/* duplicates frame if needed */
for (i = 0; i < nb_frames; i++) {
@ -1112,6 +1075,7 @@ static void do_video_out(AVFormatContext *s,
#endif
return;
#if FF_API_LAVF_FMT_RAWPICTURE
if (s->oformat->flags & AVFMT_RAWPICTURE &&
enc->codec->id == AV_CODEC_ID_RAWVIDEO) {
/* raw pictures are written as AVPicture structure to
@ -1127,7 +1091,9 @@ static void do_video_out(AVFormatContext *s,
pkt.flags |= AV_PKT_FLAG_KEY;
write_frame(s, &pkt, ost);
} else {
} else
#endif
{
int got_packet, forced_keyframe = 0;
double pts_time;
@ -1254,7 +1220,7 @@ static void do_video_out(AVFormatContext *s,
static double psnr(double d)
{
return -10.0 * log(d) / log(10.0);
return -10.0 * log10(d);
}
static void do_video_stats(OutputStream *ost, int frame_size)
@ -1536,10 +1502,13 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
AVCodecContext *enc;
int frame_number, vid, i;
double bitrate;
int64_t pts = INT64_MIN;
double speed;
int64_t pts = INT64_MIN + 1;
static int64_t last_time = -1;
static int qp_histogram[52];
int hours, mins, secs, us;
int ret;
float t;
if (!print_stats && !is_last_report && !progress_avio)
return;
@ -1554,6 +1523,8 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
last_time = cur_time;
}
t = (cur_time-timer_start) / 1000000.0;
oc = output_files[0]->ctx;
@ -1577,7 +1548,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
ost->file_index, ost->index, q);
}
if (!vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) {
float fps, t = (cur_time-timer_start) / 1000000.0;
float fps;
frame_number = ost->frame_number;
fps = t > 1 ? frame_number / t : 0;
@ -1595,7 +1566,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
if (qp >= 0 && qp < FF_ARRAY_ELEMS(qp_histogram))
qp_histogram[qp]++;
for (j = 0; j < 32; j++)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%X", (int)lrintf(log2(qp_histogram[j] + 1)));
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%X", av_log2(qp_histogram[j] + 1));
}
if ((enc->flags & AV_CODEC_FLAG_PSNR) && (ost->pict_type != AV_PICTURE_TYPE_NONE || is_last_report)) {
@ -1634,7 +1605,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
pts = FFMAX(pts, av_rescale_q(av_stream_get_end_pts(ost->st),
ost->st->time_base, AV_TIME_BASE_Q));
if (is_last_report)
nb_frames_drop += ost->last_droped;
nb_frames_drop += ost->last_dropped;
}
secs = FFABS(pts) / AV_TIME_BASE;
@ -1645,6 +1616,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
mins %= 60;
bitrate = pts && total_size >= 0 ? total_size * 8 / (pts / 1000.0) : -1;
speed = t != 0.0 ? (double)pts / AV_TIME_BASE / t : -1;
if (total_size < 0) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"size=N/A time=");
@ -1676,6 +1648,14 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
av_bprintf(&buf_script, "dup_frames=%d\n", nb_frames_dup);
av_bprintf(&buf_script, "drop_frames=%d\n", nb_frames_drop);
if (speed < 0) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf)," speed=N/A");
av_bprintf(&buf_script, "speed=N/A\n");
} else {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf)," speed=%4.3gx", speed);
av_bprintf(&buf_script, "speed=%4.3gx\n", speed);
}
if (print_stats || is_last_report) {
const char end = is_last_report ? '\n' : '\r';
if (print_stats==1 && AV_LOG_INFO > av_log_get_level()) {
@ -1694,7 +1674,9 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
avio_flush(progress_avio);
av_bprint_finalize(&buf_script, NULL);
if (is_last_report) {
avio_closep(&progress_avio);
if ((ret = avio_closep(&progress_avio)) < 0)
av_log(NULL, AV_LOG_ERROR,
"Error closing progress log, loss of information possible: %s\n", av_err2str(ret));
}
}
@ -1717,8 +1699,10 @@ static void flush_encoders(void)
if (enc->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1)
continue;
#if FF_API_LAVF_FMT_RAWPICTURE
if (enc->codec_type == AVMEDIA_TYPE_VIDEO && (os->oformat->flags & AVFMT_RAWPICTURE) && enc->codec->id == AV_CODEC_ID_RAWVIDEO)
continue;
#endif
for (;;) {
int (*encode)(AVCodecContext*, AVPacket*, const AVFrame*, int*) = NULL;
@ -1727,11 +1711,11 @@ static void flush_encoders(void)
switch (enc->codec_type) {
case AVMEDIA_TYPE_AUDIO:
encode = avcodec_encode_audio2;
desc = "Audio";
desc = "audio";
break;
case AVMEDIA_TYPE_VIDEO:
encode = avcodec_encode_video2;
desc = "Video";
desc = "video";
break;
default:
stop_encoding = 1;
@ -1747,7 +1731,7 @@ static void flush_encoders(void)
update_benchmark(NULL);
ret = encode(enc, &pkt, NULL, &got_packet);
update_benchmark("flush %s %d.%d", desc, ost->file_index, ost->index);
update_benchmark("flush_%s %d.%d", desc, ost->file_index, ost->index);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "%s encoding failed: %s\n",
desc,
@ -1762,7 +1746,7 @@ static void flush_encoders(void)
break;
}
if (ost->finished & MUXER_FINISHED) {
av_free_packet(&pkt);
av_packet_unref(&pkt);
continue;
}
av_packet_rescale_ts(&pkt, enc->time_base, ost->st->time_base);
@ -1805,7 +1789,6 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
InputFile *f = input_files [ist->file_index];
int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time;
int64_t ost_tb_start_time = av_rescale_q(start_time, AV_TIME_BASE_Q, ost->st->time_base);
int64_t ist_tb_start_time = av_rescale_q(start_time, AV_TIME_BASE_Q, ist->st->time_base);
AVPicture pict;
AVPacket opkt;
@ -1815,13 +1798,13 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
!ost->copy_initial_nonkeyframes)
return;
if (pkt->pts == AV_NOPTS_VALUE) {
if (!ost->frame_number && ist->pts < start_time &&
!ost->copy_prior_start)
return;
} else {
if (!ost->frame_number && pkt->pts < ist_tb_start_time &&
!ost->copy_prior_start)
if (!ost->frame_number && !ost->copy_prior_start) {
int64_t comp_start = start_time;
if (copy_ts && f->start_time != AV_NOPTS_VALUE)
comp_start = FFMAX(start_time, f->start_time + f->ts_offset);
if (pkt->pts == AV_NOPTS_VALUE ?
ist->pts < comp_start :
pkt->pts < av_rescale_q(comp_start, AV_TIME_BASE_Q, ist->st->time_base))
return;
}
@ -1833,7 +1816,7 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
if (f->recording_time != INT64_MAX) {
start_time = f->ctx->start_time;
if (f->start_time != AV_NOPTS_VALUE)
if (f->start_time != AV_NOPTS_VALUE && copy_ts)
start_time += f->start_time;
if (ist->pts >= f->recording_time + start_time) {
close_output_stream(ost);
@ -1893,6 +1876,7 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
}
av_copy_packet_side_data(&opkt, pkt);
#if FF_API_LAVF_FMT_RAWPICTURE
if (ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO &&
ost->st->codec->codec_id == AV_CODEC_ID_RAWVIDEO &&
(of->ctx->oformat->flags & AVFMT_RAWPICTURE)) {
@ -1907,6 +1891,7 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p
opkt.size = sizeof(AVPicture);
opkt.flags |= AV_PKT_FLAG_KEY;
}
#endif
write_frame(of->ctx, &opkt, ost);
}
@ -1931,6 +1916,22 @@ int guess_input_channel_layout(InputStream *ist)
return 1;
}
static void check_decode_result(InputStream *ist, int *got_output, int ret)
{
if (*got_output || ret<0)
decode_error_stat[ret<0] ++;
if (ret < 0 && exit_on_error)
exit_program(1);
if (exit_on_error && *got_output && ist) {
if (av_frame_get_decode_error_flags(ist->decoded_frame) || (ist->decoded_frame->flags & AV_FRAME_FLAG_CORRUPT)) {
av_log(NULL, AV_LOG_FATAL, "%s: corrupt decoded frame in stream %d\n", input_files[ist->file_index]->ctx->filename, ist->st->index);
exit_program(1);
}
}
}
static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
{
AVFrame *decoded_frame, *f;
@ -1953,11 +1954,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
ret = AVERROR_INVALIDDATA;
}
if (*got_output || ret<0)
decode_error_stat[ret<0] ++;
if (ret < 0 && exit_on_error)
exit_program(1);
check_decode_result(ist, got_output, ret);
if (!*got_output || ret < 0)
return ret;
@ -2037,6 +2034,7 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output)
decoded_frame->pts = av_rescale_delta(decoded_frame_tb, decoded_frame->pts,
(AVRational){1, avctx->sample_rate}, decoded_frame->nb_samples, &ist->filter_in_rescale_delta_last,
(AVRational){1, avctx->sample_rate});
ist->nb_samples = decoded_frame->nb_samples;
for (i = 0; i < ist->nb_filters; i++) {
if (i < ist->nb_filters - 1) {
f = ist->filter_frame;
@ -2093,11 +2091,7 @@ static int decode_video(InputStream *ist, AVPacket *pkt, int *got_output)
ist->st->codec->has_b_frames);
}
if (*got_output || ret<0)
decode_error_stat[ret<0] ++;
if (ret < 0 && exit_on_error)
exit_program(1);
check_decode_result(ist, got_output, ret);
if (*got_output && ret >= 0) {
if (ist->dec_ctx->width != decoded_frame->width ||
@ -2205,11 +2199,7 @@ static int transcode_subtitles(InputStream *ist, AVPacket *pkt, int *got_output)
int i, ret = avcodec_decode_subtitle2(ist->dec_ctx,
&subtitle, got_output, pkt);
if (*got_output || ret<0)
decode_error_stat[ret<0] ++;
if (ret < 0 && exit_on_error)
exit_program(1);
check_decode_result(NULL, got_output, ret);
if (ret < 0 || !*got_output) {
if (!pkt->size)
@ -2274,7 +2264,7 @@ static int send_filter_eof(InputStream *ist)
}
/* pkt = NULL means EOF (needed to flush decoder buffers) */
static int process_input_packet(InputStream *ist, const AVPacket *pkt)
static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
{
int ret = 0, i;
int got_output = 0;
@ -2383,7 +2373,8 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt)
}
/* after flushing, send an EOF on all the filter inputs attached to the stream */
if (!pkt && ist->decoding_needed && !got_output) {
/* except when looping we need to flush but not to send an EOF */
if (!pkt && ist->decoding_needed && !got_output && !no_eof) {
int ret = send_filter_eof(ist);
if (ret < 0) {
av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n");
@ -2582,8 +2573,7 @@ static InputStream *get_input_stream(OutputStream *ost)
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;
return FFDIFFSIGN(*(const int64_t *)a, *(const int64_t *)b);
}
static int init_output_stream(OutputStream *ost, char *error, int error_len)
@ -2607,7 +2597,6 @@ static int init_output_stream(OutputStream *ost, char *error, int error_len)
}
if (!av_dict_get(ost->encoder_opts, "threads", NULL, 0))
av_dict_set(&ost->encoder_opts, "threads", "auto", 0);
av_dict_set(&ost->encoder_opts, "side_data_only_packets", "1", 0);
if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
!codec->defaults &&
!av_dict_get(ost->encoder_opts, "b", NULL, 0) &&
@ -2639,6 +2628,28 @@ static int init_output_stream(OutputStream *ost, char *error, int error_len)
exit_program(1);
}
if (ost->enc_ctx->nb_coded_side_data) {
int i;
ost->st->side_data = av_realloc_array(NULL, ost->enc_ctx->nb_coded_side_data,
sizeof(*ost->st->side_data));
if (!ost->st->side_data)
return AVERROR(ENOMEM);
for (i = 0; i < ost->enc_ctx->nb_coded_side_data; i++) {
const AVPacketSideData *sd_src = &ost->enc_ctx->coded_side_data[i];
AVPacketSideData *sd_dst = &ost->st->side_data[i];
sd_dst->data = av_malloc(sd_src->size);
if (!sd_dst->data)
return AVERROR(ENOMEM);
memcpy(sd_dst->data, sd_src->data, sd_src->size);
sd_dst->size = sd_src->size;
sd_dst->type = sd_src->type;
ost->st->nb_side_data++;
}
}
// copy timebase while removing common factors
ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 1});
ost->st->codec->codec= ost->enc_ctx->codec;
@ -2965,6 +2976,7 @@ static int transcode_init(void)
enc_ctx->audio_service_type = dec_ctx->audio_service_type;
enc_ctx->block_align = dec_ctx->block_align;
enc_ctx->initial_padding = dec_ctx->delay;
enc_ctx->profile = dec_ctx->profile;
#if FF_API_AUDIOENC_DELAY
enc_ctx->delay = dec_ctx->delay;
#endif
@ -3017,6 +3029,11 @@ static int transcode_init(void)
set_encoder_id(output_files[ost->file_index], ost);
#if CONFIG_LIBMFX
if (qsv_transcode_init(ost))
exit_program(1);
#endif
if (!ost->filter &&
(enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
enc_ctx->codec_type == AVMEDIA_TYPE_AUDIO)) {
@ -3371,8 +3388,12 @@ static OutputStream *choose_output(void)
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,
int64_t opts = ost->st->cur_dts == AV_NOPTS_VALUE ? INT64_MIN :
av_rescale_q(ost->st->cur_dts, ost->st->time_base,
AV_TIME_BASE_Q);
if (ost->st->cur_dts == AV_NOPTS_VALUE)
av_log(NULL, AV_LOG_DEBUG, "cur_dts is invalid (this is harmless if it occurs once at the start per stream)\n");
if (!ost->finished && opts < opts_min) {
opts_min = opts;
ost_min = ost->unavailable ? NULL : ost;
@ -3381,6 +3402,18 @@ static OutputStream *choose_output(void)
return ost_min;
}
static void set_tty_echo(int on)
{
#if HAVE_TERMIOS_H
struct termios tty;
if (tcgetattr(0, &tty) == 0) {
if (on) tty.c_lflag |= ECHO;
else tty.c_lflag &= ~ECHO;
tcsetattr(0, TCSANOW, &tty);
}
#endif
}
static int check_keyboard_interaction(int64_t cur_time)
{
int i, ret, key;
@ -3413,10 +3446,13 @@ static int check_keyboard_interaction(int64_t cur_time)
int k, n = 0;
fprintf(stderr, "\nEnter command: <target>|all <time>|-1 <command>[ <argument>]\n");
i = 0;
set_tty_echo(1);
while ((k = read_key()) != '\n' && k != '\r' && i < sizeof(buf)-1)
if (k > 0)
buf[i++] = k;
buf[i] = 0;
set_tty_echo(0);
fprintf(stderr, "\n");
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",
@ -3455,10 +3491,13 @@ static int check_keyboard_interaction(int64_t cur_time)
char buf[32];
int k = 0;
i = 0;
set_tty_echo(1);
while ((k = read_key()) != '\n' && k != '\r' && i < sizeof(buf)-1)
if (k > 0)
buf[i++] = k;
buf[i] = 0;
set_tty_echo(0);
fprintf(stderr, "\n");
if (k <= 0 || sscanf(buf, "%d", &debug)!=1)
fprintf(stderr,"error parsing debug value\n");
}
@ -3507,7 +3546,6 @@ static void *input_thread(void *arg)
av_thread_message_queue_set_err_recv(f->in_thread_queue, ret);
break;
}
av_dup_packet(&pkt);
ret = av_thread_message_queue_send(f->in_thread_queue, &pkt, flags);
if (flags && ret == AVERROR(EAGAIN)) {
flags = 0;
@ -3522,7 +3560,7 @@ static void *input_thread(void *arg)
av_log(f->ctx, AV_LOG_ERROR,
"Unable to send packet to main thread: %s\n",
av_err2str(ret));
av_free_packet(&pkt);
av_packet_unref(&pkt);
av_thread_message_queue_set_err_recv(f->in_thread_queue, ret);
break;
}
@ -3543,7 +3581,7 @@ static void free_input_threads(void)
continue;
av_thread_message_queue_set_err_send(f->in_thread_queue, AVERROR_EOF);
while (av_thread_message_queue_recv(f->in_thread_queue, &pkt, 0) >= 0)
av_free_packet(&pkt);
av_packet_unref(&pkt);
pthread_join(f->thread, NULL);
f->joined = 1;
@ -3624,6 +3662,87 @@ static void reset_eagain(void)
output_streams[i]->unavailable = 0;
}
// set duration to max(tmp, duration) in a proper time base and return duration's time_base
static AVRational duration_max(int64_t tmp, int64_t *duration, AVRational tmp_time_base,
AVRational time_base)
{
int ret;
if (!*duration) {
*duration = tmp;
return tmp_time_base;
}
ret = av_compare_ts(*duration, time_base, tmp, tmp_time_base);
if (ret < 0) {
*duration = tmp;
return tmp_time_base;
}
return time_base;
}
static int seek_to_start(InputFile *ifile, AVFormatContext *is)
{
InputStream *ist;
AVCodecContext *avctx;
int i, ret, has_audio = 0;
int64_t duration = 0;
ret = av_seek_frame(is, -1, is->start_time, 0);
if (ret < 0)
return ret;
for (i = 0; i < ifile->nb_streams; i++) {
ist = input_streams[ifile->ist_index + i];
avctx = ist->dec_ctx;
// flush decoders
if (ist->decoding_needed) {
process_input_packet(ist, NULL, 1);
avcodec_flush_buffers(avctx);
}
/* duration is the length of the last frame in a stream
* when audio stream is present we don't care about
* last video frame length because it's not defined exactly */
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && ist->nb_samples)
has_audio = 1;
}
for (i = 0; i < ifile->nb_streams; i++) {
ist = input_streams[ifile->ist_index + i];
avctx = ist->dec_ctx;
if (has_audio) {
if (avctx->codec_type == AVMEDIA_TYPE_AUDIO && ist->nb_samples) {
AVRational sample_rate = {1, avctx->sample_rate};
duration = av_rescale_q(ist->nb_samples, sample_rate, ist->st->time_base);
} else
continue;
} else {
if (ist->framerate.num) {
duration = av_rescale_q(1, ist->framerate, ist->st->time_base);
} else if (ist->st->avg_frame_rate.num) {
duration = av_rescale_q(1, ist->st->avg_frame_rate, ist->st->time_base);
} else duration = 1;
}
if (!ifile->duration)
ifile->time_base = ist->st->time_base;
/* the total duration of the stream, max_pts - min_pts is
* the duration of the stream without the last frame */
duration += ist->max_pts - ist->min_pts;
ifile->time_base = duration_max(duration, &ifile->duration, ist->st->time_base,
ifile->time_base);
}
if (ifile->loop > 0)
ifile->loop--;
return ret;
}
/*
* Return
* - 0 -- one packet was read and processed
@ -3638,6 +3757,8 @@ static int process_input(int file_index)
InputStream *ist;
AVPacket pkt;
int ret, i, j;
int64_t duration;
int64_t pkt_dts;
is = ifile->ctx;
ret = get_input_packet(ifile, &pkt);
@ -3646,6 +3767,11 @@ static int process_input(int file_index)
ifile->eagain = 1;
return ret;
}
if (ret < 0 && ifile->loop) {
if ((ret = seek_to_start(ifile, is)) < 0)
return ret;
ret = get_input_packet(ifile, &pkt);
}
if (ret < 0) {
if (ret != AVERROR_EOF) {
print_error(is->filename, ret);
@ -3656,7 +3782,7 @@ static int process_input(int file_index)
for (i = 0; i < ifile->nb_streams; i++) {
ist = input_streams[ifile->ist_index + i];
if (ist->decoding_needed) {
ret = process_input_packet(ist, NULL);
ret = process_input_packet(ist, NULL, 0);
if (ret>0)
return 0;
}
@ -3678,7 +3804,7 @@ static int process_input(int file_index)
reset_eagain();
if (do_pkt_dump) {
av_pkt_dump_log2(NULL, AV_LOG_DEBUG, &pkt, do_hex_dump,
av_pkt_dump_log2(NULL, AV_LOG_INFO, &pkt, do_hex_dump,
is->streams[pkt.stream_index]);
}
/* the following test is needed in case new streams appear
@ -3696,6 +3822,11 @@ static int process_input(int file_index)
if (ist->discard)
goto discard_packet;
if (exit_on_error && (pkt.flags & AV_PKT_FLAG_CORRUPT)) {
av_log(NULL, AV_LOG_FATAL, "%s: corrupt input packet in stream %d\n", is->filename, pkt.stream_index);
exit_program(1);
}
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",
@ -3774,11 +3905,11 @@ static int process_input(int file_index)
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts *= ist->ts_scale;
pkt_dts = av_rescale_q_rnd(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
pkt.dts != AV_NOPTS_VALUE && ist->next_dts == AV_NOPTS_VALUE && !copy_ts
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){
@ -3792,11 +3923,21 @@ static int process_input(int file_index)
}
}
duration = av_rescale_q(ifile->duration, ifile->time_base, ist->st->time_base);
if (pkt.pts != AV_NOPTS_VALUE) {
pkt.pts += duration;
ist->max_pts = FFMAX(pkt.pts, ist->max_pts);
ist->min_pts = FFMIN(pkt.pts, ist->min_pts);
}
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts += duration;
pkt_dts = av_rescale_q_rnd(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
if ((ist->dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO ||
ist->dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) &&
pkt.dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE &&
pkt_dts != AV_NOPTS_VALUE && ist->next_dts != AV_NOPTS_VALUE &&
!copy_ts) {
int64_t pkt_dts = av_rescale_q(pkt.dts, ist->st->time_base, AV_TIME_BASE_Q);
int64_t delta = pkt_dts - ist->next_dts;
if (is->iformat->flags & AVFMT_TS_DISCONT) {
if (delta < -1LL*dts_delta_threshold*AV_TIME_BASE ||
@ -3842,10 +3983,10 @@ static int process_input(int file_index)
sub2video_heartbeat(ist, pkt.pts);
process_input_packet(ist, &pkt);
process_input_packet(ist, &pkt, 0);
discard_packet:
av_free_packet(&pkt);
av_packet_unref(&pkt);
return 0;
}
@ -3953,6 +4094,7 @@ static int transcode(void)
OutputStream *ost;
InputStream *ist;
int64_t timer_start;
int64_t total_packets_written = 0;
ret = transcode_init();
if (ret < 0)
@ -3984,16 +4126,12 @@ static int transcode(void)
}
ret = transcode_step();
if (ret < 0) {
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) {
continue;
} else {
char errbuf[128];
av_strerror(ret, errbuf, sizeof(errbuf));
if (ret < 0 && ret != AVERROR_EOF) {
char errbuf[128];
av_strerror(ret, errbuf, sizeof(errbuf));
av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", errbuf);
break;
}
av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", errbuf);
break;
}
/* dump report by using the output first video and audio streams */
@ -4007,7 +4145,7 @@ static int transcode(void)
for (i = 0; i < nb_input_streams; i++) {
ist = input_streams[i];
if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) {
process_input_packet(ist, NULL);
process_input_packet(ist, NULL, 0);
}
}
flush_encoders();
@ -4017,7 +4155,11 @@ static int transcode(void)
/* write the trailer if needed and close file */
for (i = 0; i < nb_output_files; i++) {
os = output_files[i]->ctx;
av_write_trailer(os);
if ((ret = av_write_trailer(os)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Error writing trailer of %s: %s", os->filename, av_err2str(ret));
if (exit_on_error)
exit_program(1);
}
}
/* dump report by using the first video and audio streams */
@ -4029,6 +4171,12 @@ static int transcode(void)
if (ost->encoding_needed) {
av_freep(&ost->enc_ctx->stats_in);
}
total_packets_written += ost->packets_written;
}
if (!total_packets_written && (abort_on_flags & ABORT_ON_FLAG_EMPTY_OUTPUT)) {
av_log(NULL, AV_LOG_FATAL, "Empty output\n");
exit_program(1);
}
/* close each decoder */
@ -4054,7 +4202,10 @@ static int transcode(void)
ost = output_streams[i];
if (ost) {
if (ost->logfile) {
fclose(ost->logfile);
if (fclose(ost->logfile))
av_log(NULL, AV_LOG_ERROR,
"Error closing logfile, loss of information possible: %s\n",
av_err2str(AVERROR(errno)));
ost->logfile = NULL;
}
av_freep(&ost->forced_kf_pts);
@ -4064,7 +4215,6 @@ static int transcode(void)
av_dict_free(&ost->sws_dict);
av_dict_free(&ost->swr_opts);
av_dict_free(&ost->resample_opts);
av_dict_free(&ost->bsf_args);
}
}
}

View File

@ -64,6 +64,7 @@ enum HWAccelID {
HWACCEL_DXVA2,
HWACCEL_VDA,
HWACCEL_VIDEOTOOLBOX,
HWACCEL_QSV,
};
typedef struct HWAccel {
@ -112,6 +113,7 @@ typedef struct OptionsContext {
/* input options */
int64_t input_ts_offset;
int loop;
int rate_emu;
int accurate_seek;
int thread_queue_size;
@ -214,6 +216,8 @@ typedef struct OptionsContext {
int nb_discard;
SpecifierOpt *disposition;
int nb_disposition;
SpecifierOpt *program;
int nb_program;
} OptionsContext;
typedef struct InputFilter {
@ -273,6 +277,10 @@ typedef struct InputStream {
int64_t filter_in_rescale_delta_last;
int64_t min_pts; /* pts with the smallest value in a current stream */
int64_t max_pts; /* pts with the higher value in a current stream */
int64_t nb_samples; /* number of samples in the last decoded audio frame before looping */
double ts_scale;
int saw_first_ts;
int showed_multi_packet_warning;
@ -342,7 +350,12 @@ typedef struct InputFile {
int eof_reached; /* true if eof reached */
int eagain; /* true if last read attempt returned EAGAIN */
int ist_index; /* index of first stream in input_streams */
int loop; /* set number of times input stream should be looped */
int64_t duration; /* actual duration of the longest stream in a file
at the moment when looping happens */
AVRational time_base; /* time base of the duration */
int64_t input_ts_offset;
int64_t ts_offset;
int64_t last_ts;
int64_t start_time; /* user-specified start time in AV_TIME_BASE or AV_NOPTS_VALUE */
@ -372,6 +385,8 @@ enum forced_keyframes_const {
FKF_NB
};
#define ABORT_ON_FLAG_EMPTY_OUTPUT (1 << 0)
extern const char *const forced_keyframes_const_names[];
typedef enum {
@ -401,11 +416,14 @@ typedef struct OutputStream {
int64_t max_frames;
AVFrame *filtered_frame;
AVFrame *last_frame;
int last_droped;
int last_dropped;
int last_nb0_frames[3];
void *hwaccel_ctx;
/* video only */
AVRational frame_rate;
int is_cfr;
int force_fps;
int top_field_first;
int rotate_overridden;
@ -436,7 +454,6 @@ typedef struct OutputStream {
AVDictionary *sws_dict;
AVDictionary *swr_opts;
AVDictionary *resample_opts;
AVDictionary *bsf_args;
char *apad;
OSTFinished finished; /* no more packets should be written for this stream */
int unavailable; /* true if the steram is unavailable (possibly temporarily) */
@ -514,6 +531,7 @@ extern int start_at_zero;
extern int copy_tb;
extern int debug_ts;
extern int exit_on_error;
extern int abort_on_flags;
extern int print_stats;
extern int qp_hist;
extern int stdin_interaction;
@ -557,5 +575,7 @@ int vdpau_init(AVCodecContext *s);
int dxva2_init(AVCodecContext *s);
int vda_init(AVCodecContext *s);
int videotoolbox_init(AVCodecContext *s);
int qsv_init(AVCodecContext *s);
int qsv_transcode_init(OutputStream *ost);
#endif /* FFMPEG_H */

View File

@ -53,6 +53,7 @@ DEFINE_GUID(DXVADDI_Intel_ModeH264_E, 0x604F8E68, 0x4951,0x4C54,0x88,0xFE,0xAB,0
DEFINE_GUID(DXVA2_ModeVC1_D, 0x1b81beA3, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
DEFINE_GUID(DXVA2_ModeVC1_D2010, 0x1b81beA4, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
DEFINE_GUID(DXVA2_ModeHEVC_VLD_Main, 0x5b11d51b, 0x2f4c,0x4452,0xbc,0xc3,0x09,0xf2,0xa1,0x16,0x0c,0xc0);
DEFINE_GUID(DXVA2_ModeVP9_VLD_Profile0, 0x463707f8, 0xa1d0,0x4585,0x87,0x6d,0x83,0xaa,0x6d,0x60,0xb8,0x9e);
DEFINE_GUID(DXVA2_NoEncrypt, 0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5);
DEFINE_GUID(GUID_NULL, 0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00);
@ -84,6 +85,9 @@ static const dxva2_mode dxva2_modes[] = {
/* HEVC/H.265 */
{ &DXVA2_ModeHEVC_VLD_Main, AV_CODEC_ID_HEVC },
/* VP8/9 */
{ &DXVA2_ModeVP9_VLD_Profile0, AV_CODEC_ID_VP9 },
{ NULL, 0 },
};
@ -543,6 +547,8 @@ static int dxva2_create_decoder(AVCodecContext *s)
/* add surfaces based on number of possible refs */
if (s->codec_id == AV_CODEC_ID_H264 || s->codec_id == AV_CODEC_ID_HEVC)
ctx->num_surfaces += 16;
else if (s->codec_id == AV_CODEC_ID_VP9)
ctx->num_surfaces += 8;
else
ctx->num_surfaces += 2;

View File

@ -38,6 +38,28 @@
#include "libavutil/imgutils.h"
#include "libavutil/samplefmt.h"
static const enum AVPixelFormat *get_compliance_unofficial_pix_fmts(enum AVCodecID codec_id, const enum AVPixelFormat default_formats[])
{
static const enum AVPixelFormat mjpeg_formats[] =
{ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P,
AV_PIX_FMT_NONE };
static const enum AVPixelFormat ljpeg_formats[] =
{ 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};
if (codec_id == AV_CODEC_ID_MJPEG) {
return mjpeg_formats;
} else if (codec_id == AV_CODEC_ID_LJPEG) {
return ljpeg_formats;
} else {
return default_formats;
}
}
enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *enc_ctx, AVCodec *codec, enum AVPixelFormat target)
{
if (codec && codec->pix_fmts) {
@ -45,18 +67,9 @@ enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *enc_ctx, AVCod
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(target);
int has_alpha = desc ? desc->nb_components % 2 == 0 : 0;
enum AVPixelFormat best= AV_PIX_FMT_NONE;
static const enum AVPixelFormat mjpeg_formats[] =
{ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_NONE };
static const enum AVPixelFormat ljpeg_formats[] =
{ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUV420P,
AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE };
if (enc_ctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
if (enc_ctx->codec_id == AV_CODEC_ID_MJPEG) {
p = mjpeg_formats;
} else if (enc_ctx->codec_id == AV_CODEC_ID_LJPEG) {
p =ljpeg_formats;
}
p = get_compliance_unofficial_pix_fmts(enc_ctx->codec_id, p);
}
for (; *p != AV_PIX_FMT_NONE; p++) {
best= avcodec_find_best_pix_fmt_of_2(best, *p, target, has_alpha, NULL);
@ -126,12 +139,7 @@ static char *choose_pix_fmts(OutputStream *ost)
p = ost->enc->pix_fmts;
if (ost->enc_ctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
if (ost->enc_ctx->codec_id == AV_CODEC_ID_MJPEG) {
p = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_NONE };
} else if (ost->enc_ctx->codec_id == AV_CODEC_ID_LJPEG) {
p = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUV420P,
AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE };
}
p = get_compliance_unofficial_pix_fmts(ost->enc_ctx->codec_id, p);
}
for (; *p != AV_PIX_FMT_NONE; p++) {
@ -1046,8 +1054,14 @@ int configure_filtergraph(FilterGraph *fg)
for (i = 0; i < fg->nb_outputs; i++) {
OutputStream *ost = fg->outputs[i]->ost;
if (ost &&
ost->enc->type == AVMEDIA_TYPE_AUDIO &&
if (!ost->enc) {
/* identical to the same check in ffmpeg.c, needed because
complex filter graphs are initialized earlier */
av_log(NULL, AV_LOG_ERROR, "Encoder (codec %s) not found for output stream #%d:%d\n",
avcodec_get_name(ost->st->codec->codec_id), ost->file_index, ost->index);
return AVERROR(EINVAL);
}
if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
!(ost->enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))
av_buffersink_set_frame_size(ost->filter->filter,
ost->enc_ctx->frame_size);

View File

@ -78,6 +78,9 @@ const HWAccel hwaccels[] = {
#endif
#if CONFIG_VIDEOTOOLBOX
{ "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX },
#endif
#if CONFIG_LIBMFX
{ "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV },
#endif
{ 0 },
};
@ -103,6 +106,7 @@ int start_at_zero = 0;
int copy_tb = -1;
int debug_ts = 0;
int exit_on_error = 0;
int abort_on_flags = 0;
int print_stats = -1;
int qp_hist = 0;
int stdin_interaction = 1;
@ -196,6 +200,24 @@ static AVDictionary *strip_specifiers(AVDictionary *dict)
return ret;
}
static int opt_abort_on(void *optctx, const char *opt, const char *arg)
{
static const AVOption opts[] = {
{ "abort_on" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" },
{ "empty_output" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = ABORT_ON_FLAG_EMPTY_OUTPUT }, .unit = "flags" },
{ NULL },
};
static const AVClass class = {
.class_name = "",
.item_name = av_default_item_name,
.option = opts,
.version = LIBAVUTIL_VERSION_INT,
};
const AVClass *pclass = &class;
return av_opt_eval_flags(&pclass, &opts[0], arg, &abort_on_flags);
}
static int opt_sameq(void *optctx, const char *opt, const char *arg)
{
av_log(NULL, AV_LOG_ERROR, "Option '%s' was removed. "
@ -627,6 +649,9 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic)
ist->file_index = nb_input_files;
ist->discard = 1;
st->discard = AVDISCARD_ALL;
ist->nb_samples = 0;
ist->min_pts = INT64_MAX;
ist->max_pts = INT64_MIN;
ist->ts_scale = 1.0;
MATCH_PER_STREAM_OPT(ts_scale, dbl, ist->ts_scale, ic, st);
@ -1005,6 +1030,9 @@ static int open_input_file(OptionsContext *o, const char *filename)
f->nb_streams = ic->nb_streams;
f->rate_emu = o->rate_emu;
f->accurate_seek = o->accurate_seek;
f->loop = o->loop;
f->duration = 0;
f->time_base = (AVRational){ 1, 1 };
#if HAVE_PTHREADS
f->thread_queue_size = o->thread_queue_size > 0 ? o->thread_queue_size : 8;
#endif
@ -1227,7 +1255,11 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
bsfc_prev->next = bsfc;
else
ost->bitstream_filters = bsfc;
av_dict_set(&ost->bsf_args, bsfc->filter->name, arg, 0);
if (arg)
if (!(bsfc->args = av_strdup(arg))) {
av_log(NULL, AV_LOG_FATAL, "Bitstream filter memory allocation failed\n");
exit_program(1);
}
bsfc_prev = bsfc;
bsf = next;
@ -2326,6 +2358,72 @@ loop_end:
}
}
/* process manually set programs */
for (i = 0; i < o->nb_program; i++) {
const char *p = o->program[i].u.str;
int progid = i+1;
AVProgram *program;
while(*p) {
const char *p2 = av_get_token(&p, ":");
const char *to_dealloc = p2;
char *key;
if (!p2)
break;
if(*p) p++;
key = av_get_token(&p2, "=");
if (!key || !*p2) {
av_freep(&to_dealloc);
av_freep(&key);
break;
}
p2++;
if (!strcmp(key, "program_num"))
progid = strtol(p2, NULL, 0);
av_freep(&to_dealloc);
av_freep(&key);
}
program = av_new_program(oc, progid);
p = o->program[i].u.str;
while(*p) {
const char *p2 = av_get_token(&p, ":");
const char *to_dealloc = p2;
char *key;
if (!p2)
break;
if(*p) p++;
key = av_get_token(&p2, "=");
if (!key) {
av_log(NULL, AV_LOG_FATAL,
"No '=' character in program string %s.\n",
p2);
exit_program(1);
}
if (!*p2)
exit_program(1);
p2++;
if (!strcmp(key, "title")) {
av_dict_set(&program->metadata, "title", p2, 0);
} else if (!strcmp(key, "program_num")) {
} else if (!strcmp(key, "st")) {
int st_num = strtol(p2, NULL, 0);
av_program_add_stream_index(oc, progid, st_num);
} else {
av_log(NULL, AV_LOG_FATAL, "Unknown program key %s.\n", key);
exit_program(1);
}
av_freep(&to_dealloc);
av_freep(&key);
}
}
/* process manually set metadata */
for (i = 0; i < o->nb_metadata; i++) {
AVDictionary **m;
@ -2378,6 +2476,13 @@ loop_end:
}
m = &oc->chapters[index]->metadata;
break;
case 'p':
if (index < 0 || index >= oc->nb_programs) {
av_log(NULL, AV_LOG_FATAL, "Invalid program index %d in metadata specifier.\n", index);
exit_program(1);
}
m = &oc->programs[index]->metadata;
break;
default:
av_log(NULL, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata[i].specifier);
exit_program(1);
@ -2823,6 +2928,7 @@ void show_help_default(const char *opt, const char *arg)
" -h -- print basic options\n"
" -h long -- print more options\n"
" -h full -- print all options (including all format and codec specific options, very long)\n"
" -h type=name -- print all options for the named decoder/encoder/demuxer/muxer/filter\n"
" See man %s for detailed description of the options.\n"
"\n", program_name);
@ -3064,6 +3170,8 @@ const OptionDef options[] = {
"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" },
{ "program", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(program) },
"add program with specified streams", "title=string:st=number..." },
{ "dframes", HAS_ARG | OPT_PERFILE | OPT_EXPERT |
OPT_OUTPUT, { .func_arg = opt_data_frames },
"set the number of data frames to output", "number" },
@ -3087,7 +3195,7 @@ const OptionDef options[] = {
{ "target", HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_target },
"specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\" or \"dv50\" "
"with optional prefixes \"pal-\", \"ntsc-\" or \"film-\")", "type" },
{ "vsync", HAS_ARG | OPT_EXPERT, { opt_vsync },
{ "vsync", HAS_ARG | OPT_EXPERT, { .func_arg = opt_vsync },
"video sync method", "" },
{ "frame_drop_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT, { &frame_drop_threshold },
"frame drop threshold", "" },
@ -3113,6 +3221,8 @@ const OptionDef options[] = {
"timestamp error delta threshold", "threshold" },
{ "xerror", OPT_BOOL | OPT_EXPERT, { &exit_on_error },
"exit on error", "error" },
{ "abort_on", HAS_ARG | OPT_EXPERT, { .func_arg = opt_abort_on },
"abort on the specified condition flags", "flags" },
{ "copyinkf", OPT_BOOL | OPT_EXPERT | OPT_SPEC |
OPT_OUTPUT, { .off = OFFSET(copy_initial_nonkeyframes) },
"copy initial non-keyframes" },
@ -3151,6 +3261,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" },
{ "stream_loop", OPT_INT | HAS_ARG | OPT_EXPERT | OPT_INPUT |
OPT_OFFSET, { .off = OFFSET(loop) }, "set number of times input stream shall be looped", "loop count" },
{ "debug_ts", OPT_BOOL | OPT_EXPERT, { &debug_ts },
"print timestamp debugging info" },
{ "max_error_rate", HAS_ARG | OPT_FLOAT, { &max_error_rate },
@ -3207,9 +3319,9 @@ const OptionDef options[] = {
"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 },
{ "vstats", OPT_VIDEO | OPT_EXPERT , { .func_arg = opt_vstats },
"dump video coding statistics to file" },
{ "vstats_file", OPT_VIDEO | HAS_ARG | OPT_EXPERT , { opt_vstats_file },
{ "vstats_file", OPT_VIDEO | HAS_ARG | OPT_EXPERT , { .func_arg = opt_vstats_file },
"dump video coding statistics to file", "file" },
{ "vf", OPT_VIDEO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_video_filters },
"set video filters", "filter_graph" },
@ -3319,7 +3431,7 @@ const OptionDef options[] = {
"set the initial demux-decode delay", "seconds" },
{ "override_ffserver", OPT_BOOL | OPT_EXPERT | OPT_OUTPUT, { &override_ffserver },
"override the options from ffserver", "" },
{ "sdp_file", HAS_ARG | OPT_EXPERT | OPT_OUTPUT, { opt_sdp_file },
{ "sdp_file", HAS_ARG | OPT_EXPERT | OPT_OUTPUT, { .func_arg = opt_sdp_file },
"specify a file in which to print sdp information", "file" },
{ "bsf", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(bitstream_filters) },

268
ffmpeg_qsv.c Normal file
View File

@ -0,0 +1,268 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <mfx/mfxvideo.h>
#include <stdlib.h>
#include "libavutil/dict.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "libavcodec/qsv.h"
#include "ffmpeg.h"
typedef struct QSVContext {
OutputStream *ost;
mfxSession session;
mfxExtOpaqueSurfaceAlloc opaque_alloc;
AVBufferRef *opaque_surfaces_buf;
uint8_t *surface_used;
mfxFrameSurface1 **surface_ptrs;
int nb_surfaces;
mfxExtBuffer *ext_buffers[1];
} QSVContext;
static void buffer_release(void *opaque, uint8_t *data)
{
*(uint8_t*)opaque = 0;
}
static int qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
{
InputStream *ist = s->opaque;
QSVContext *qsv = ist->hwaccel_ctx;
int i;
for (i = 0; i < qsv->nb_surfaces; i++) {
if (qsv->surface_used[i])
continue;
frame->buf[0] = av_buffer_create((uint8_t*)qsv->surface_ptrs[i], sizeof(*qsv->surface_ptrs[i]),
buffer_release, &qsv->surface_used[i], 0);
if (!frame->buf[0])
return AVERROR(ENOMEM);
frame->data[3] = (uint8_t*)qsv->surface_ptrs[i];
qsv->surface_used[i] = 1;
return 0;
}
return AVERROR(ENOMEM);
}
static int init_opaque_surf(QSVContext *qsv)
{
AVQSVContext *hwctx_enc = qsv->ost->enc_ctx->hwaccel_context;
mfxFrameSurface1 *surfaces;
int i;
qsv->nb_surfaces = hwctx_enc->nb_opaque_surfaces;
qsv->opaque_surfaces_buf = av_buffer_ref(hwctx_enc->opaque_surfaces);
qsv->surface_ptrs = av_mallocz_array(qsv->nb_surfaces, sizeof(*qsv->surface_ptrs));
qsv->surface_used = av_mallocz_array(qsv->nb_surfaces, sizeof(*qsv->surface_used));
if (!qsv->opaque_surfaces_buf || !qsv->surface_ptrs || !qsv->surface_used)
return AVERROR(ENOMEM);
surfaces = (mfxFrameSurface1*)qsv->opaque_surfaces_buf->data;
for (i = 0; i < qsv->nb_surfaces; i++)
qsv->surface_ptrs[i] = surfaces + i;
qsv->opaque_alloc.Out.Surfaces = qsv->surface_ptrs;
qsv->opaque_alloc.Out.NumSurface = qsv->nb_surfaces;
qsv->opaque_alloc.Out.Type = hwctx_enc->opaque_alloc_type;
qsv->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
qsv->opaque_alloc.Header.BufferSz = sizeof(qsv->opaque_alloc);
qsv->ext_buffers[0] = (mfxExtBuffer*)&qsv->opaque_alloc;
return 0;
}
static void qsv_uninit(AVCodecContext *s)
{
InputStream *ist = s->opaque;
QSVContext *qsv = ist->hwaccel_ctx;
av_freep(&qsv->ost->enc_ctx->hwaccel_context);
av_freep(&s->hwaccel_context);
av_buffer_unref(&qsv->opaque_surfaces_buf);
av_freep(&qsv->surface_used);
av_freep(&qsv->surface_ptrs);
av_freep(&qsv);
}
int qsv_init(AVCodecContext *s)
{
InputStream *ist = s->opaque;
QSVContext *qsv = ist->hwaccel_ctx;
AVQSVContext *hwctx_dec;
int ret;
if (!qsv) {
av_log(NULL, AV_LOG_ERROR, "QSV transcoding is not initialized. "
"-hwaccel qsv should only be used for one-to-one QSV transcoding "
"with no filters.\n");
return AVERROR_BUG;
}
ret = init_opaque_surf(qsv);
if (ret < 0)
return ret;
hwctx_dec = av_qsv_alloc_context();
if (!hwctx_dec)
return AVERROR(ENOMEM);
hwctx_dec->session = qsv->session;
hwctx_dec->iopattern = MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
hwctx_dec->ext_buffers = qsv->ext_buffers;
hwctx_dec->nb_ext_buffers = FF_ARRAY_ELEMS(qsv->ext_buffers);
av_freep(&s->hwaccel_context);
s->hwaccel_context = hwctx_dec;
ist->hwaccel_get_buffer = qsv_get_buffer;
ist->hwaccel_uninit = qsv_uninit;
return 0;
}
static mfxIMPL choose_implementation(const InputStream *ist)
{
static const struct {
const char *name;
mfxIMPL impl;
} impl_map[] = {
{ "auto", MFX_IMPL_AUTO },
{ "sw", MFX_IMPL_SOFTWARE },
{ "hw", MFX_IMPL_HARDWARE },
{ "auto_any", MFX_IMPL_AUTO_ANY },
{ "hw_any", MFX_IMPL_HARDWARE_ANY },
{ "hw2", MFX_IMPL_HARDWARE2 },
{ "hw3", MFX_IMPL_HARDWARE3 },
{ "hw4", MFX_IMPL_HARDWARE4 },
};
mfxIMPL impl = MFX_IMPL_AUTO_ANY;
int i;
if (ist->hwaccel_device) {
for (i = 0; i < FF_ARRAY_ELEMS(impl_map); i++)
if (!strcmp(ist->hwaccel_device, impl_map[i].name)) {
impl = impl_map[i].impl;
break;
}
if (i == FF_ARRAY_ELEMS(impl_map))
impl = strtol(ist->hwaccel_device, NULL, 0);
}
return impl;
}
int qsv_transcode_init(OutputStream *ost)
{
InputStream *ist;
const enum AVPixelFormat *pix_fmt;
AVDictionaryEntry *e;
const AVOption *opt;
int flags = 0;
int err, i;
QSVContext *qsv = NULL;
AVQSVContext *hwctx = NULL;
mfxIMPL impl;
mfxVersion ver = { { 3, 1 } };
/* check if the encoder supports QSV */
if (!ost->enc->pix_fmts)
return 0;
for (pix_fmt = ost->enc->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++)
if (*pix_fmt == AV_PIX_FMT_QSV)
break;
if (*pix_fmt == AV_PIX_FMT_NONE)
return 0;
if (strcmp(ost->avfilter, "null") || ost->source_index < 0)
return 0;
/* check if the decoder supports QSV and the output only goes to this stream */
ist = input_streams[ost->source_index];
if (ist->nb_filters || ist->hwaccel_id != HWACCEL_QSV ||
!ist->dec || !ist->dec->pix_fmts)
return 0;
for (pix_fmt = ist->dec->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++)
if (*pix_fmt == AV_PIX_FMT_QSV)
break;
if (*pix_fmt == AV_PIX_FMT_NONE)
return 0;
for (i = 0; i < nb_output_streams; i++)
if (output_streams[i] != ost &&
output_streams[i]->source_index == ost->source_index)
return 0;
av_log(NULL, AV_LOG_VERBOSE, "Setting up QSV transcoding\n");
qsv = av_mallocz(sizeof(*qsv));
hwctx = av_qsv_alloc_context();
if (!qsv || !hwctx)
goto fail;
impl = choose_implementation(ist);
err = MFXInit(impl, &ver, &qsv->session);
if (err != MFX_ERR_NONE) {
av_log(NULL, AV_LOG_ERROR, "Error initializing an MFX session: %d\n", err);
goto fail;
}
e = av_dict_get(ost->encoder_opts, "flags", NULL, 0);
opt = av_opt_find(ost->enc_ctx, "flags", NULL, 0, 0);
if (e && opt)
av_opt_eval_flags(ost->enc_ctx, opt, e->value, &flags);
qsv->ost = ost;
hwctx->session = qsv->session;
hwctx->iopattern = MFX_IOPATTERN_IN_OPAQUE_MEMORY;
hwctx->opaque_alloc = 1;
hwctx->nb_opaque_surfaces = 16;
ost->hwaccel_ctx = qsv;
ost->enc_ctx->hwaccel_context = hwctx;
ost->enc_ctx->pix_fmt = AV_PIX_FMT_QSV;
ist->hwaccel_ctx = qsv;
ist->dec_ctx->pix_fmt = AV_PIX_FMT_QSV;
ist->resample_pix_fmt = AV_PIX_FMT_QSV;
return 0;
fail:
av_freep(&hwctx);
av_freep(&qsv);
return AVERROR_UNKNOWN;
}

View File

@ -16,9 +16,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <CoreServices/CoreServices.h>
#include "config.h"
#if HAVE_UTGETOSTYPEFROMSTRING
#include <CoreServices/CoreServices.h>
#endif
#include "libavcodec/avcodec.h"
#if CONFIG_VDA
# include "libavcodec/vda.h"
@ -154,7 +157,13 @@ int videotoolbox_init(AVCodecContext *s)
CFStringRef pixfmt_str = CFStringCreateWithCString(kCFAllocatorDefault,
videotoolbox_pixfmt,
kCFStringEncodingUTF8);
#if HAVE_UTGETOSTYPEFROMSTRING
vtctx->cv_pix_fmt_type = UTGetOSTypeFromString(pixfmt_str);
#else
av_log(s, loglevel, "UTGetOSTypeFromString() is not available "
"on this platform, %s pixel format can not be honored from "
"the command line\n", videotoolbox_pixfmt);
#endif
ret = av_videotoolbox_default_init2(s, vtctx);
CFRelease(pixfmt_str);
}
@ -168,7 +177,13 @@ int videotoolbox_init(AVCodecContext *s)
CFStringRef pixfmt_str = CFStringCreateWithCString(kCFAllocatorDefault,
videotoolbox_pixfmt,
kCFStringEncodingUTF8);
#if HAVE_UTGETOSTYPEFROMSTRING
vdactx->cv_pix_fmt_type = UTGetOSTypeFromString(pixfmt_str);
#else
av_log(s, loglevel, "UTGetOSTypeFromString() is not available "
"on this platform, %s pixel format can not be honored from "
"the command line\n", videotoolbox_pixfmt);
#endif
ret = av_vda_default_init2(s, vdactx);
CFRelease(pixfmt_str);
}

385
ffplay.c
View File

@ -48,7 +48,6 @@
#include "libswresample/swresample.h"
#if CONFIG_AVFILTER
# include "libavfilter/avcodec.h"
# include "libavfilter/avfilter.h"
# include "libavfilter/buffersink.h"
# include "libavfilter/buffersrc.h"
@ -74,6 +73,9 @@ const int program_birth_year = 2003;
/* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */
#define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30
/* Step size for volume control */
#define SDL_VOLUME_STEP (SDL_MIX_MAXVOLUME / 50)
/* no AV sync correction is done if below the minimum AV sync threshold */
#define AV_SYNC_THRESHOLD_MIN 0.04
/* AV sync correction is done if above the maximum AV sync threshold */
@ -149,6 +151,7 @@ typedef struct Clock {
typedef struct Frame {
AVFrame *frame;
AVSubtitle sub;
AVSubtitleRect **subrects; /* rescaled subtitle rectangles in yuva */
int serial;
double pts; /* presentation timestamp for the frame */
double duration; /* estimated duration of the frame */
@ -247,6 +250,8 @@ typedef struct VideoState {
unsigned int audio_buf1_size;
int audio_buf_index; /* in bytes */
int audio_write_buf_size;
int audio_volume;
int muted;
struct AudioParams audio_src;
#if CONFIG_AVFILTER
struct AudioParams audio_filter_src;
@ -286,7 +291,7 @@ typedef struct VideoState {
SDL_Rect last_display_rect;
int eof;
char filename[1024];
char *filename;
int width, height, xleft, ytop;
int step;
@ -422,16 +427,12 @@ 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);
av_packet_unref(pkt);
return ret;
}
@ -447,12 +448,21 @@ static int packet_queue_put_nullpacket(PacketQueue *q, int stream_index)
}
/* packet queue handling */
static void packet_queue_init(PacketQueue *q)
static int packet_queue_init(PacketQueue *q)
{
memset(q, 0, sizeof(PacketQueue));
q->mutex = SDL_CreateMutex();
if (!q->mutex) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
return AVERROR(ENOMEM);
}
q->cond = SDL_CreateCond();
if (!q->cond) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
return AVERROR(ENOMEM);
}
q->abort_request = 1;
return 0;
}
static void packet_queue_flush(PacketQueue *q)
@ -462,7 +472,7 @@ static void packet_queue_flush(PacketQueue *q)
SDL_LockMutex(q->mutex);
for (pkt = q->first_pkt; pkt; pkt = pkt1) {
pkt1 = pkt->next;
av_free_packet(&pkt->pkt);
av_packet_unref(&pkt->pkt);
av_freep(&pkt);
}
q->last_pkt = NULL;
@ -567,7 +577,7 @@ static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {
d->next_pts_tb = d->start_pts_tb;
}
} while (pkt.data == flush_pkt.data || d->queue->serial != d->pkt_serial);
av_free_packet(&d->pkt);
av_packet_unref(&d->pkt);
d->pkt_temp = d->pkt = pkt;
d->packet_pending = 1;
}
@ -631,11 +641,17 @@ static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {
}
static void decoder_destroy(Decoder *d) {
av_free_packet(&d->pkt);
av_packet_unref(&d->pkt);
}
static void frame_queue_unref_item(Frame *vp)
{
int i;
for (i = 0; i < vp->sub.num_rects; i++) {
av_freep(&vp->subrects[i]->data[0]);
av_freep(&vp->subrects[i]);
}
av_freep(&vp->subrects);
av_frame_unref(vp->frame);
avsubtitle_free(&vp->sub);
}
@ -644,10 +660,14 @@ static int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int
{
int i;
memset(f, 0, sizeof(FrameQueue));
if (!(f->mutex = SDL_CreateMutex()))
if (!(f->mutex = SDL_CreateMutex())) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
return AVERROR(ENOMEM);
if (!(f->cond = SDL_CreateCond()))
}
if (!(f->cond = SDL_CreateCond())) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
return AVERROR(ENOMEM);
}
f->pktq = pktq;
f->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE);
f->keep_last = !!keep_last;
@ -838,20 +858,20 @@ static void fill_border(int xleft, int ytop, int width, int height, int x, int y
#define BPP 1
static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw, int imgh)
static void blend_subrect(uint8_t **data, int *linesize, const AVSubtitleRect *rect, int imgw, int imgh)
{
int x, y, Y, U, V, A;
uint8_t *lum, *cb, *cr;
int dstx, dsty, dstw, dsth;
const AVPicture *src = &rect->pict;
const AVSubtitleRect *src = rect;
dstw = av_clip(rect->w, 0, imgw);
dsth = av_clip(rect->h, 0, imgh);
dstx = av_clip(rect->x, 0, imgw - dstw);
dsty = av_clip(rect->y, 0, imgh - dsth);
lum = dst->data[0] + dstx + dsty * dst->linesize[0];
cb = dst->data[1] + dstx/2 + (dsty >> 1) * dst->linesize[1];
cr = dst->data[2] + dstx/2 + (dsty >> 1) * dst->linesize[2];
lum = data[0] + dstx + dsty * linesize[0];
cb = data[1] + dstx/2 + (dsty >> 1) * linesize[1];
cr = data[2] + dstx/2 + (dsty >> 1) * linesize[2];
for (y = 0; y<dsth; y++) {
for (x = 0; x<dstw; x++) {
@ -860,7 +880,7 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw,
lum[0] = ALPHA_BLEND(A, lum[0], Y, 0);
lum++;
}
lum += dst->linesize[0] - dstw;
lum += linesize[0] - dstw;
}
for (y = 0; y<dsth/2; y++) {
@ -876,8 +896,8 @@ static void blend_subrect(AVPicture *dst, const AVSubtitleRect *rect, int imgw,
cb++;
cr++;
}
cb += dst->linesize[1] - dstw/2;
cr += dst->linesize[2] - dstw/2;
cb += linesize[1] - dstw/2;
cr += linesize[2] - dstw/2;
}
}
@ -907,10 +927,10 @@ static void calculate_display_rect(SDL_Rect *rect,
/* XXX: we suppose the screen has a 1.0 pixel ratio */
height = scr_height;
width = ((int)rint(height * aspect_ratio)) & ~1;
width = lrint(height * aspect_ratio) & ~1;
if (width > scr_width) {
width = scr_width;
height = ((int)rint(width / aspect_ratio)) & ~1;
height = lrint(width / aspect_ratio) & ~1;
}
x = (scr_width - width) / 2;
y = (scr_height - height) / 2;
@ -924,7 +944,6 @@ static void video_image_display(VideoState *is)
{
Frame *vp;
Frame *sp;
AVPicture pict;
SDL_Rect rect;
int i;
@ -935,18 +954,21 @@ static void video_image_display(VideoState *is)
sp = frame_queue_peek(&is->subpq);
if (vp->pts >= sp->pts + ((float) sp->sub.start_display_time / 1000)) {
uint8_t *data[4];
int linesize[4];
SDL_LockYUVOverlay (vp->bmp);
pict.data[0] = vp->bmp->pixels[0];
pict.data[1] = vp->bmp->pixels[2];
pict.data[2] = vp->bmp->pixels[1];
data[0] = vp->bmp->pixels[0];
data[1] = vp->bmp->pixels[2];
data[2] = vp->bmp->pixels[1];
pict.linesize[0] = vp->bmp->pitches[0];
pict.linesize[1] = vp->bmp->pitches[2];
pict.linesize[2] = vp->bmp->pitches[1];
linesize[0] = vp->bmp->pitches[0];
linesize[1] = vp->bmp->pitches[2];
linesize[2] = vp->bmp->pitches[1];
for (i = 0; i < sp->sub.num_rects; i++)
blend_subrect(&pict, sp->sub.rects[i],
blend_subrect(data, linesize, sp->subrects[i],
vp->bmp->w, vp->bmp->h);
SDL_UnlockYUVOverlay (vp->bmp);
@ -1095,9 +1117,9 @@ static void video_audio_display(VideoState *s)
* directly access it but it is more than fast enough. */
for (y = 0; y < s->height; y++) {
double w = 1 / sqrt(nb_freq);
int a = sqrt(w * sqrt(data[0][2 * y + 0] * data[0][2 * y + 0] + data[0][2 * y + 1] * data[0][2 * y + 1]));
int b = (nb_display_channels == 2 ) ? sqrt(w * sqrt(data[1][2 * y + 0] * data[1][2 * y + 0]
+ data[1][2 * y + 1] * data[1][2 * y + 1])) : a;
int a = sqrt(w * hypot(data[0][2 * y + 0], data[0][2 * y + 1]));
int b = (nb_display_channels == 2 ) ? sqrt(w * hypot(data[1][2 * y + 0], data[1][2 * y + 1]))
: a;
a = FFMIN(a, 255);
b = FFMIN(b, 255);
fgcolor = SDL_MapRGB(screen->format, a, b, (a + b) / 2);
@ -1115,11 +1137,80 @@ static void video_audio_display(VideoState *s)
}
}
static void stream_component_close(VideoState *is, int stream_index)
{
AVFormatContext *ic = is->ic;
AVCodecContext *avctx;
if (stream_index < 0 || stream_index >= ic->nb_streams)
return;
avctx = ic->streams[stream_index]->codec;
switch (avctx->codec_type) {
case AVMEDIA_TYPE_AUDIO:
decoder_abort(&is->auddec, &is->sampq);
SDL_CloseAudio();
decoder_destroy(&is->auddec);
swr_free(&is->swr_ctx);
av_freep(&is->audio_buf1);
is->audio_buf1_size = 0;
is->audio_buf = NULL;
if (is->rdft) {
av_rdft_end(is->rdft);
av_freep(&is->rdft_data);
is->rdft = NULL;
is->rdft_bits = 0;
}
break;
case AVMEDIA_TYPE_VIDEO:
decoder_abort(&is->viddec, &is->pictq);
decoder_destroy(&is->viddec);
break;
case AVMEDIA_TYPE_SUBTITLE:
decoder_abort(&is->subdec, &is->subpq);
decoder_destroy(&is->subdec);
break;
default:
break;
}
ic->streams[stream_index]->discard = AVDISCARD_ALL;
avcodec_close(avctx);
switch (avctx->codec_type) {
case AVMEDIA_TYPE_AUDIO:
is->audio_st = NULL;
is->audio_stream = -1;
break;
case AVMEDIA_TYPE_VIDEO:
is->video_st = NULL;
is->video_stream = -1;
break;
case AVMEDIA_TYPE_SUBTITLE:
is->subtitle_st = NULL;
is->subtitle_stream = -1;
break;
default:
break;
}
}
static void stream_close(VideoState *is)
{
/* XXX: use a special url_shutdown call to abort parse cleanly */
is->abort_request = 1;
SDL_WaitThread(is->read_tid, NULL);
/* close each stream */
if (is->audio_stream >= 0)
stream_component_close(is, is->audio_stream);
if (is->video_stream >= 0)
stream_component_close(is, is->video_stream);
if (is->subtitle_stream >= 0)
stream_component_close(is, is->subtitle_stream);
avformat_close_input(&is->ic);
packet_queue_destroy(&is->videoq);
packet_queue_destroy(&is->audioq);
packet_queue_destroy(&is->subtitleq);
@ -1133,6 +1224,7 @@ static void stream_close(VideoState *is)
sws_freeContext(is->img_convert_ctx);
#endif
sws_freeContext(is->sub_convert_ctx);
av_free(is->filename);
av_free(is);
}
@ -1349,6 +1441,16 @@ static void toggle_pause(VideoState *is)
is->step = 0;
}
static void toggle_mute(VideoState *is)
{
is->muted = !is->muted;
}
static void update_volume(VideoState *is, int sign, int step)
{
is->audio_volume = av_clip(is->audio_volume + sign * step, 0, SDL_MIX_MAXVOLUME);
}
static void step_to_next_frame(VideoState *is)
{
/* if the stream is paused unpause it, then step */
@ -1660,22 +1762,23 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double
/* if the frame is not skipped, then display it */
if (vp->bmp) {
AVPicture pict = { { 0 } };
uint8_t *data[4];
int linesize[4];
/* get a pointer on the bitmap */
SDL_LockYUVOverlay (vp->bmp);
pict.data[0] = vp->bmp->pixels[0];
pict.data[1] = vp->bmp->pixels[2];
pict.data[2] = vp->bmp->pixels[1];
data[0] = vp->bmp->pixels[0];
data[1] = vp->bmp->pixels[2];
data[2] = vp->bmp->pixels[1];
pict.linesize[0] = vp->bmp->pitches[0];
pict.linesize[1] = vp->bmp->pitches[2];
pict.linesize[2] = vp->bmp->pitches[1];
linesize[0] = vp->bmp->pitches[0];
linesize[1] = vp->bmp->pitches[2];
linesize[2] = vp->bmp->pitches[1];
#if CONFIG_AVFILTER
// FIXME use direct rendering
av_picture_copy(&pict, (AVPicture *)src_frame,
av_image_copy(data, linesize, (const uint8_t **)src_frame->data, src_frame->linesize,
src_frame->format, vp->width, vp->height);
#else
{
@ -1698,7 +1801,7 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts, double
exit(1);
}
sws_scale(is->img_convert_ctx, src_frame->data, src_frame->linesize,
0, vp->height, pict.data, pict.linesize);
0, vp->height, data, linesize);
#endif
/* workaround SDL PITCH_WORKAROUND */
duplicate_right_border_pixels(vp->bmp);
@ -2056,10 +2159,15 @@ static int audio_thread(void *arg)
return ret;
}
static void decoder_start(Decoder *d, int (*fn)(void *), void *arg)
static int decoder_start(Decoder *d, int (*fn)(void *), void *arg)
{
packet_queue_start(d->queue);
d->decoder_tid = SDL_CreateThread(fn, arg);
if (!d->decoder_tid) {
av_log(NULL, AV_LOG_ERROR, "SDL_CreateThread(): %s\n", SDL_GetError());
return AVERROR(ENOMEM);
}
return 0;
}
static int video_thread(void *arg)
@ -2193,6 +2301,10 @@ static int subtitle_thread(void *arg)
pts = sp->sub.pts / (double)AV_TIME_BASE;
sp->pts = pts;
sp->serial = is->subdec.pkt_serial;
if (!(sp->subrects = av_mallocz_array(sp->sub.num_rects, sizeof(AVSubtitleRect*)))) {
av_log(NULL, AV_LOG_FATAL, "Cannot allocate subrects\n");
exit(1);
}
for (i = 0; i < sp->sub.num_rects; i++)
{
@ -2202,35 +2314,28 @@ static int subtitle_thread(void *arg)
int subh = is->subdec.avctx->height ? is->subdec.avctx->height : is->viddec_height;
int out_w = is->viddec_width ? in_w * is->viddec_width / subw : in_w;
int out_h = is->viddec_height ? in_h * is->viddec_height / subh : in_h;
AVPicture newpic;
//can not use avpicture_alloc as it is not compatible with avsubtitle_free()
av_image_fill_linesizes(newpic.linesize, AV_PIX_FMT_YUVA420P, out_w);
newpic.data[0] = av_malloc(newpic.linesize[0] * out_h);
newpic.data[3] = av_malloc(newpic.linesize[3] * out_h);
newpic.data[1] = av_malloc(newpic.linesize[1] * ((out_h+1)/2));
newpic.data[2] = av_malloc(newpic.linesize[2] * ((out_h+1)/2));
if (!(sp->subrects[i] = av_mallocz(sizeof(AVSubtitleRect))) ||
av_image_alloc(sp->subrects[i]->data, sp->subrects[i]->linesize, out_w, out_h, AV_PIX_FMT_YUVA420P, 16) < 0) {
av_log(NULL, AV_LOG_FATAL, "Cannot allocate subtitle data\n");
exit(1);
}
is->sub_convert_ctx = sws_getCachedContext(is->sub_convert_ctx,
in_w, in_h, AV_PIX_FMT_PAL8, out_w, out_h,
AV_PIX_FMT_YUVA420P, sws_flags, NULL, NULL, NULL);
if (!is->sub_convert_ctx || !newpic.data[0] || !newpic.data[3] ||
!newpic.data[1] || !newpic.data[2]
) {
if (!is->sub_convert_ctx) {
av_log(NULL, AV_LOG_FATAL, "Cannot initialize the sub conversion context\n");
exit(1);
}
sws_scale(is->sub_convert_ctx,
(void*)sp->sub.rects[i]->pict.data, sp->sub.rects[i]->pict.linesize,
0, in_h, newpic.data, newpic.linesize);
(void*)sp->sub.rects[i]->data, sp->sub.rects[i]->linesize,
0, in_h, sp->subrects[i]->data, sp->subrects[i]->linesize);
av_free(sp->sub.rects[i]->pict.data[0]);
av_free(sp->sub.rects[i]->pict.data[1]);
sp->sub.rects[i]->pict = newpic;
sp->sub.rects[i]->w = out_w;
sp->sub.rects[i]->h = out_h;
sp->sub.rects[i]->x = sp->sub.rects[i]->x * out_w / in_w;
sp->sub.rects[i]->y = sp->sub.rects[i]->y * out_h / in_h;
sp->subrects[i]->w = out_w;
sp->subrects[i]->h = out_h;
sp->subrects[i]->x = sp->sub.rects[i]->x * out_w / in_w;
sp->subrects[i]->y = sp->sub.rects[i]->y * out_h / in_h;
}
/* now we can update the picture count */
@ -2448,7 +2553,13 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len)
len1 = is->audio_buf_size - is->audio_buf_index;
if (len1 > len)
len1 = len;
memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
if (!is->muted && is->audio_volume == SDL_MIX_MAXVOLUME)
memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);
else {
memset(stream, is->silence_buf[0], len1);
if (!is->muted)
SDL_MixAudio(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1, is->audio_volume);
}
len -= len1;
stream += len1;
is->audio_buf_index += len1;
@ -2651,7 +2762,8 @@ static int stream_component_open(VideoState *is, int stream_index)
is->auddec.start_pts = is->audio_st->start_time;
is->auddec.start_pts_tb = is->audio_st->time_base;
}
decoder_start(&is->auddec, audio_thread, is);
if ((ret = decoder_start(&is->auddec, audio_thread, is)) < 0)
goto fail;
SDL_PauseAudio(0);
break;
case AVMEDIA_TYPE_VIDEO:
@ -2662,7 +2774,8 @@ static int stream_component_open(VideoState *is, int stream_index)
is->viddec_height = avctx->height;
decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread);
decoder_start(&is->viddec, video_thread, is);
if ((ret = decoder_start(&is->viddec, video_thread, is)) < 0)
goto fail;
is->queue_attachments_req = 1;
break;
case AVMEDIA_TYPE_SUBTITLE:
@ -2670,7 +2783,8 @@ static int stream_component_open(VideoState *is, int stream_index)
is->subtitle_st = ic->streams[stream_index];
decoder_init(&is->subdec, avctx, &is->subtitleq, is->continue_read_thread);
decoder_start(&is->subdec, subtitle_thread, is);
if ((ret = decoder_start(&is->subdec, subtitle_thread, is)) < 0)
goto fail;
break;
default:
break;
@ -2682,64 +2796,6 @@ fail:
return ret;
}
static void stream_component_close(VideoState *is, int stream_index)
{
AVFormatContext *ic = is->ic;
AVCodecContext *avctx;
if (stream_index < 0 || stream_index >= ic->nb_streams)
return;
avctx = ic->streams[stream_index]->codec;
switch (avctx->codec_type) {
case AVMEDIA_TYPE_AUDIO:
decoder_abort(&is->auddec, &is->sampq);
SDL_CloseAudio();
decoder_destroy(&is->auddec);
swr_free(&is->swr_ctx);
av_freep(&is->audio_buf1);
is->audio_buf1_size = 0;
is->audio_buf = NULL;
if (is->rdft) {
av_rdft_end(is->rdft);
av_freep(&is->rdft_data);
is->rdft = NULL;
is->rdft_bits = 0;
}
break;
case AVMEDIA_TYPE_VIDEO:
decoder_abort(&is->viddec, &is->pictq);
decoder_destroy(&is->viddec);
break;
case AVMEDIA_TYPE_SUBTITLE:
decoder_abort(&is->subdec, &is->subpq);
decoder_destroy(&is->subdec);
break;
default:
break;
}
ic->streams[stream_index]->discard = AVDISCARD_ALL;
avcodec_close(avctx);
switch (avctx->codec_type) {
case AVMEDIA_TYPE_AUDIO:
is->audio_st = NULL;
is->audio_stream = -1;
break;
case AVMEDIA_TYPE_VIDEO:
is->video_st = NULL;
is->video_stream = -1;
break;
case AVMEDIA_TYPE_SUBTITLE:
is->subtitle_st = NULL;
is->subtitle_stream = -1;
break;
default:
break;
}
}
static int decode_interrupt_cb(void *ctx)
{
VideoState *is = ctx;
@ -2779,6 +2835,12 @@ static int read_thread(void *arg)
int scan_all_pmts_set = 0;
int64_t pkt_ts;
if (!wait_mutex) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
ret = AVERROR(ENOMEM);
goto fail;
}
memset(st_index, -1, sizeof(st_index));
is->last_video_stream = is->video_stream = -1;
is->last_audio_stream = is->audio_stream = -1;
@ -3060,27 +3122,14 @@ static int read_thread(void *arg)
} else if (pkt->stream_index == is->subtitle_stream && pkt_in_play_range) {
packet_queue_put(&is->subtitleq, pkt);
} else {
av_free_packet(pkt);
av_packet_unref(pkt);
}
}
/* wait until the end */
while (!is->abort_request) {
SDL_Delay(100);
}
ret = 0;
fail:
/* close each stream */
if (is->audio_stream >= 0)
stream_component_close(is, is->audio_stream);
if (is->video_stream >= 0)
stream_component_close(is, is->video_stream);
if (is->subtitle_stream >= 0)
stream_component_close(is, is->subtitle_stream);
if (ic) {
if (ic && !is->ic)
avformat_close_input(&ic);
is->ic = NULL;
}
if (ret != 0) {
SDL_Event event;
@ -3100,7 +3149,9 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
is = av_mallocz(sizeof(VideoState));
if (!is)
return NULL;
av_strlcpy(is->filename, filename, sizeof(is->filename));
is->filename = av_strdup(filename);
if (!is->filename)
goto fail;
is->iformat = iformat;
is->ytop = 0;
is->xleft = 0;
@ -3113,19 +3164,26 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat)
if (frame_queue_init(&is->sampq, &is->audioq, SAMPLE_QUEUE_SIZE, 1) < 0)
goto fail;
packet_queue_init(&is->videoq);
packet_queue_init(&is->audioq);
packet_queue_init(&is->subtitleq);
if (packet_queue_init(&is->videoq) < 0 ||
packet_queue_init(&is->audioq) < 0 ||
packet_queue_init(&is->subtitleq) < 0)
goto fail;
is->continue_read_thread = SDL_CreateCond();
if (!(is->continue_read_thread = SDL_CreateCond())) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
goto fail;
}
init_clock(&is->vidclk, &is->videoq.serial);
init_clock(&is->audclk, &is->audioq.serial);
init_clock(&is->extclk, &is->extclk.serial);
is->audio_clock_serial = -1;
is->audio_volume = SDL_MIX_MAXVOLUME;
is->muted = 0;
is->av_sync_type = av_sync_type;
is->read_tid = SDL_CreateThread(read_thread, is);
if (!is->read_tid) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateThread(): %s\n", SDL_GetError());
fail:
stream_close(is);
return NULL;
@ -3312,6 +3370,17 @@ static void event_loop(VideoState *cur_stream)
case SDLK_SPACE:
toggle_pause(cur_stream);
break;
case SDLK_m:
toggle_mute(cur_stream);
break;
case SDLK_KP_MULTIPLY:
case SDLK_0:
update_volume(cur_stream, 1, SDL_VOLUME_STEP);
break;
case SDLK_KP_DIVIDE:
case SDLK_9:
update_volume(cur_stream, -1, SDL_VOLUME_STEP);
break;
case SDLK_s: // S: Step to next frame
step_to_next_frame(cur_stream);
break;
@ -3404,6 +3473,16 @@ static void event_loop(VideoState *cur_stream)
do_exit(cur_stream);
break;
}
if (event.button.button == SDL_BUTTON_LEFT) {
static int64_t last_mouse_left_click = 0;
if (av_gettime_relative() - last_mouse_left_click <= 500000) {
toggle_full_screen(cur_stream);
cur_stream->force_refresh = 1;
last_mouse_left_click = 0;
} else {
last_mouse_left_click = av_gettime_relative();
}
}
case SDL_MOUSEMOTION:
if (cursor_hidden) {
SDL_ShowCursor(1);
@ -3411,9 +3490,11 @@ static void event_loop(VideoState *cur_stream)
}
cursor_last_shown = av_gettime_relative();
if (event.type == SDL_MOUSEBUTTONDOWN) {
if (event.button.button != SDL_BUTTON_RIGHT)
break;
x = event.button.x;
} else {
if (event.motion.state != SDL_PRESSED)
if (!(event.motion.state & SDL_BUTTON_RMASK))
break;
x = event.motion.x;
}
@ -3645,6 +3726,9 @@ void show_help_default(const char *opt, const char *arg)
"q, ESC quit\n"
"f toggle full screen\n"
"p, SPC pause\n"
"m toggle mute\n"
"9, 0 decrease and increase volume respectively\n"
"/, * decrease and increase volume respectively\n"
"a cycle audio channel in the current program\n"
"v cycle video channel\n"
"t cycle subtitle channel in the current program\n"
@ -3654,7 +3738,8 @@ void show_help_default(const char *opt, const char *arg)
"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"
"right mouse click seek to percentage in file corresponding to fraction of width\n"
"left double-click toggle full screen\n"
);
}
@ -3663,8 +3748,10 @@ static int lockmgr(void **mtx, enum AVLockOp op)
switch(op) {
case AV_LOCK_CREATE:
*mtx = SDL_CreateMutex();
if(!*mtx)
if(!*mtx) {
av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
return 1;
}
return 0;
case AV_LOCK_OBTAIN:
return !!SDL_LockMutex(*mtx);
@ -3741,6 +3828,8 @@ int main(int argc, char **argv)
SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
SDL_EventState(SDL_USEREVENT, SDL_IGNORE);
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
if (av_lockmgr_register(lockmgr)) {
av_log(NULL, AV_LOG_FATAL, "Could not initialize lock manager!\n");
do_exit(NULL);

133
ffprobe.c
View File

@ -77,6 +77,7 @@ static int do_show_format_tags = 0;
static int do_show_frame_tags = 0;
static int do_show_program_tags = 0;
static int do_show_stream_tags = 0;
static int do_show_packet_tags = 0;
static int show_value_unit = 0;
static int use_value_prefix = 0;
@ -135,6 +136,7 @@ typedef enum {
SECTION_ID_LIBRARY_VERSION,
SECTION_ID_LIBRARY_VERSIONS,
SECTION_ID_PACKET,
SECTION_ID_PACKET_TAGS,
SECTION_ID_PACKETS,
SECTION_ID_PACKETS_AND_FRAMES,
SECTION_ID_PACKET_SIDE_DATA_LIST,
@ -178,7 +180,8 @@ static struct section sections[] = {
[SECTION_ID_LIBRARY_VERSION] = { SECTION_ID_LIBRARY_VERSION, "library_version", 0, { -1 } },
[SECTION_ID_PACKETS] = { SECTION_ID_PACKETS, "packets", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
[SECTION_ID_PACKETS_AND_FRAMES] = { SECTION_ID_PACKETS_AND_FRAMES, "packets_and_frames", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET, -1} },
[SECTION_ID_PACKET] = { SECTION_ID_PACKET, "packet", 0, { SECTION_ID_PACKET_SIDE_DATA_LIST, -1 } },
[SECTION_ID_PACKET] = { SECTION_ID_PACKET, "packet", 0, { SECTION_ID_PACKET_TAGS, SECTION_ID_PACKET_SIDE_DATA_LIST, -1 } },
[SECTION_ID_PACKET_TAGS] = { SECTION_ID_PACKET_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "packet_tags" },
[SECTION_ID_PACKET_SIDE_DATA_LIST] ={ SECTION_ID_PACKET_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PACKET_SIDE_DATA, -1 } },
[SECTION_ID_PACKET_SIDE_DATA] = { SECTION_ID_PACKET_SIDE_DATA, "side_data", 0, { -1 } },
[SECTION_ID_PIXEL_FORMATS] = { SECTION_ID_PIXEL_FORMATS, "pixel_formats", SECTION_FLAG_IS_ARRAY, { SECTION_ID_PIXEL_FORMAT, -1 } },
@ -215,8 +218,19 @@ static AVInputFormat *iformat = NULL;
static struct AVHashContext *hash;
static const char *const binary_unit_prefixes [] = { "", "Ki", "Mi", "Gi", "Ti", "Pi" };
static const char *const decimal_unit_prefixes[] = { "", "K" , "M" , "G" , "T" , "P" };
static const struct {
double bin_val;
double dec_val;
const char *bin_str;
const char *dec_str;
} si_prefixes[] = {
{ 1.0, 1.0, "", "" },
{ 1.024e3, 1e3, "Ki", "K" },
{ 1.048576e6, 1e6, "Mi", "M" },
{ 1.073741824e9, 1e9, "Gi", "G" },
{ 1.099511627776e12, 1e12, "Ti", "T" },
{ 1.125899906842624e15, 1e15, "Pi", "P" },
};
static const char unit_second_str[] = "s" ;
static const char unit_hertz_str[] = "Hz" ;
@ -270,14 +284,14 @@ static char *value_string(char *buf, int buf_size, struct unit_value uv)
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];
index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1);
vald /= si_prefixes[index].bin_val;
prefix_string = si_prefixes[index].bin_str;
} 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];
index = av_clip(index, 0, FF_ARRAY_ELEMS(si_prefixes) - 1);
vald /= si_prefixes[index].dec_val;
prefix_string = si_prefixes[index].dec_str;
}
vali = vald;
}
@ -807,10 +821,10 @@ typedef struct 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 },
{ "noprint_wrappers", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
{ "nw", "do not print headers and footers", OFFSET(noprint_wrappers), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
{ "nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
{ "nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
{NULL},
};
@ -963,12 +977,12 @@ typedef struct CompactContext {
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 },
{"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
{"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.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 },
{"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
{"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
{NULL},
};
@ -1079,12 +1093,12 @@ static const Writer compact_writer = {
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 },
{"nokey", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
{"nk", "force no key printing", OFFSET(nokey), AV_OPT_TYPE_BOOL, {.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 },
{"print_section", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
{"p", "print section name", OFFSET(print_section), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
{NULL},
};
@ -1117,8 +1131,8 @@ typedef struct FlatContext {
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 },
{"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
{"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
{NULL},
};
@ -1237,8 +1251,8 @@ typedef struct INIContext {
#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 },
{"hierarchical", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
{"h", "specify if the section specification should be hierarchical", OFFSET(hierarchical), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1 },
{NULL},
};
@ -1343,8 +1357,8 @@ typedef struct JSONContext {
#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 },
{ "compact", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
{ "c", "enable compact output", OFFSET(compact), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
{ NULL }
};
@ -1506,10 +1520,10 @@ typedef struct XMLContext {
#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 },
{"fully_qualified", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
{"q", "specify if the output should be fully qualified", OFFSET(fully_qualified), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
{"xsd_strict", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
{"x", "ensure that the output is XSD compliant", OFFSET(xsd_strict), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1 },
{NULL},
};
@ -1762,6 +1776,16 @@ static void show_packet(WriterContext *w, AVFormatContext *fmt_ctx, AVPacket *pk
if (pkt->side_data_elems) {
int i;
int size;
const uint8_t *side_metadata;
side_metadata = av_packet_get_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, &size);
if (side_metadata && size && do_show_packet_tags) {
AVDictionary *dict = NULL;
if (av_packet_unpack_dictionary(side_metadata, size, &dict) >= 0)
show_tags(w, dict, SECTION_ID_PACKET_TAGS);
av_dict_free(&dict);
}
writer_print_section_header(w, SECTION_ID_PACKET_SIDE_DATA_LIST);
for (i = 0; i < pkt->side_data_elems; i++) {
AVPacketSideData *sd = &pkt->side_data[i];
@ -1814,6 +1838,7 @@ static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,
AVFormatContext *fmt_ctx)
{
AVBPrint pbuf;
char val_str[128];
const char *s;
int i;
@ -1836,7 +1861,7 @@ static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,
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));
if (av_frame_get_pkt_size(frame) != -1) print_val ("pkt_size", av_frame_get_pkt_size(frame), unit_byte_str);
else print_str_opt("pkt_size", "N/A");
switch (stream->codec->codec_type) {
@ -1890,9 +1915,12 @@ static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream,
print_str("side_data_type", name ? name : "unknown");
print_int("side_data_size", sd->size);
if (sd->type == AV_FRAME_DATA_DISPLAYMATRIX && sd->size >= 9*4) {
abort();
writer_print_integers(w, "displaymatrix", sd->data, 9, " %11d", 3, 4, 1);
print_int("rotation", av_display_rotation_get((int32_t *)sd->data));
} else if (sd->type == AV_FRAME_DATA_GOP_TIMECODE && sd->size >= 8) {
char tcbuf[AV_TIMECODE_STR_SIZE];
av_timecode_make_mpeg_tc_string(tcbuf, *(int64_t *)(sd->data));
print_str("timecode", tcbuf);
}
writer_print_section_footer(w);
}
@ -2056,7 +2084,7 @@ static int read_interval_packets(WriterContext *w, AVFormatContext *fmt_ctx,
while (pkt1.size && process_frame(w, fmt_ctx, frame, &pkt1) > 0);
}
}
av_free_packet(&pkt);
av_packet_unref(&pkt);
}
av_init_packet(&pkt);
pkt.data = NULL;
@ -2136,10 +2164,16 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id
}
}
if (dec && (profile = av_get_profile_name(dec, dec_ctx->profile)))
if (!do_bitexact && dec && (profile = av_get_profile_name(dec, dec_ctx->profile)))
print_str("profile", profile);
else
print_str_opt("profile", "unknown");
else {
if (dec_ctx->profile != FF_PROFILE_UNKNOWN) {
char profile_num[12];
snprintf(profile_num, sizeof(profile_num), "%d", dec_ctx->profile);
print_str("profile", profile_num);
} else
print_str_opt("profile", "unknown");
}
s = av_get_media_type_string(dec_ctx->codec_type);
if (s) print_str ("codec_type", s);
@ -2197,6 +2231,7 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id
else
print_str_opt("chroma_location", av_chroma_location_name(dec_ctx->chroma_sample_location));
#if FF_API_PRIVATE_OPT
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);
@ -2204,6 +2239,7 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id
} else {
print_str_opt("timecode", "N/A");
}
#endif
print_int("refs", dec_ctx->refs);
break;
@ -2722,7 +2758,7 @@ static void ffprobe_show_pixel_formats(WriterContext *w)
for (i = 0; i < pixdesc->nb_components; i++) {
writer_print_section_header(w, SECTION_ID_PIXEL_FORMAT_COMPONENT);
print_int("index", i + 1);
print_int("bit_depth", pixdesc->comp[i].depth_minus1 + 1);
print_int("bit_depth", pixdesc->comp[i].depth);
writer_print_section_footer(w);
}
writer_print_section_footer(w);
@ -3062,16 +3098,16 @@ static int opt_show_versions(const char *opt, const char *arg)
return 0; \
}
DEFINE_OPT_SHOW_SECTION(chapters, CHAPTERS);
DEFINE_OPT_SHOW_SECTION(error, ERROR);
DEFINE_OPT_SHOW_SECTION(format, FORMAT);
DEFINE_OPT_SHOW_SECTION(frames, FRAMES);
DEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS);
DEFINE_OPT_SHOW_SECTION(packets, PACKETS);
DEFINE_OPT_SHOW_SECTION(pixel_formats, PIXEL_FORMATS);
DEFINE_OPT_SHOW_SECTION(program_version, PROGRAM_VERSION);
DEFINE_OPT_SHOW_SECTION(streams, STREAMS);
DEFINE_OPT_SHOW_SECTION(programs, PROGRAMS);
DEFINE_OPT_SHOW_SECTION(chapters, CHAPTERS)
DEFINE_OPT_SHOW_SECTION(error, ERROR)
DEFINE_OPT_SHOW_SECTION(format, FORMAT)
DEFINE_OPT_SHOW_SECTION(frames, FRAMES)
DEFINE_OPT_SHOW_SECTION(library_versions, LIBRARY_VERSIONS)
DEFINE_OPT_SHOW_SECTION(packets, PACKETS)
DEFINE_OPT_SHOW_SECTION(pixel_formats, PIXEL_FORMATS)
DEFINE_OPT_SHOW_SECTION(program_version, PROGRAM_VERSION)
DEFINE_OPT_SHOW_SECTION(streams, STREAMS)
DEFINE_OPT_SHOW_SECTION(programs, PROGRAMS)
static const OptionDef real_options[] = {
#include "cmdutils_common_opts.h"
@ -3178,6 +3214,7 @@ int main(int argc, char **argv)
SET_DO_SHOW(FRAME_TAGS, frame_tags);
SET_DO_SHOW(PROGRAM_TAGS, program_tags);
SET_DO_SHOW(STREAM_TAGS, stream_tags);
SET_DO_SHOW(PACKET_TAGS, packet_tags);
if (do_bitexact && (do_show_program_version || do_show_library_versions)) {
av_log(NULL, AV_LOG_ERROR,

View File

@ -71,6 +71,8 @@
#include "cmdutils.h"
#include "ffserver_config.h"
#define PATH_LENGTH 1024
const char program_name[] = "ffserver";
const int program_birth_year = 2000;
@ -240,6 +242,11 @@ static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
static int rtp_new_av_stream(HTTPContext *c,
int stream_index, struct sockaddr_in *dest_addr,
HTTPContext *rtsp_c);
/* utils */
static size_t htmlencode (const char *src, char **dest);
static inline void cp_html_entity (char *buffer, const char *entity);
static inline int check_codec_match(AVCodecContext *ccf, AVCodecContext *ccs,
int stream);
static const char *my_program_name;
@ -258,12 +265,79 @@ static AVLFG random_state;
static FILE *logfile = NULL;
static void htmlstrip(char *s) {
while (s && *s) {
s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
if (*s)
*s++ = '?';
static inline void cp_html_entity (char *buffer, const char *entity) {
if (!buffer || !entity)
return;
while (*entity)
*buffer++ = *entity++;
}
/**
* Substitutes known conflicting chars on a text string with
* their corresponding HTML entities.
*
* Returns the number of bytes in the 'encoded' representation
* not including the terminating NUL.
*/
static size_t htmlencode (const char *src, char **dest) {
const char *amp = "&amp;";
const char *lt = "&lt;";
const char *gt = "&gt;";
const char *start;
char *tmp;
size_t final_size = 0;
if (!src)
return 0;
start = src;
/* Compute needed dest size */
while (*src != '\0') {
switch(*src) {
case 38: /* & */
final_size += 5;
break;
case 60: /* < */
case 62: /* > */
final_size += 4;
break;
default:
final_size++;
}
src++;
}
src = start;
*dest = av_mallocz(final_size + 1);
if (!*dest)
return 0;
/* Build dest */
tmp = *dest;
while (*src != '\0') {
switch(*src) {
case 38: /* & */
cp_html_entity (tmp, amp);
tmp += 5;
break;
case 60: /* < */
cp_html_entity (tmp, lt);
tmp += 4;
break;
case 62: /* > */
cp_html_entity (tmp, gt);
tmp += 4;
break;
default:
*tmp = *src;
tmp += 1;
}
src++;
}
*tmp = '\0';
return final_size;
}
static int64_t ffm_read_write_index(int fd)
@ -285,29 +359,37 @@ static int ffm_write_write_index(int fd, int64_t pos)
for(i=0;i<8;i++)
buf[i] = (pos >> (56 - i * 8)) & 0xff;
if (lseek(fd, 8, SEEK_SET) < 0)
return AVERROR(EIO);
goto bail_eio;
if (write(fd, buf, 8) != 8)
return AVERROR(EIO);
goto bail_eio;
return 8;
bail_eio:
return AVERROR(EIO);
}
static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
int64_t file_size)
{
FFMContext *ffm = s->priv_data;
ffm->write_index = pos;
ffm->file_size = file_size;
av_opt_set_int(s, "server_attached", 1, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(s, "write_index", pos, AV_OPT_SEARCH_CHILDREN);
av_opt_set_int(s, "file_size", file_size, AV_OPT_SEARCH_CHILDREN);
}
static char *ctime1(char *buf2, int buf_size)
static char *ctime1(char *buf2, size_t buf_size)
{
time_t ti;
char *p;
ti = time(NULL);
p = ctime(&ti);
if (!p || !*p) {
*buf2 = '\0';
return buf2;
}
av_strlcpy(buf2, p, buf_size);
p = buf2 + strlen(p) - 1;
p = buf2 + strlen(buf2) - 1;
if (*p == '\n')
*p = '\0';
return buf2;
@ -388,16 +470,33 @@ static int compute_datarate(DataRateData *drd, int64_t count)
static void start_children(FFServerStream *feed)
{
char pathname[1024];
char *pathname;
char *slash;
int i;
size_t cmd_length;
if (no_launch)
return;
cmd_length = strlen(my_program_name);
/**
* FIXME: WIP Safeguard. Remove after clearing all harcoded
* '1024' path lengths
*/
if (cmd_length > PATH_LENGTH - 1) {
http_log("Could not start children. Command line: '%s' exceeds "
"path length limit (%d)\n", my_program_name, PATH_LENGTH);
return;
}
pathname = av_strdup (my_program_name);
if (!pathname) {
http_log("Could not allocate memory for children cmd line\n");
return;
}
/* replace "ffserver" with "ffmpeg" in the path of current
* program. Ignore user provided path */
av_strlcpy(pathname, my_program_name, sizeof(pathname));
slash = strrchr(pathname, '/');
if (!slash)
@ -415,8 +514,9 @@ static void start_children(FFServerStream *feed)
feed->pid = fork();
if (feed->pid < 0) {
http_log("Unable to create children\n");
exit(1);
http_log("Unable to create children: %s\n", strerror(errno));
av_free (pathname);
exit(EXIT_FAILURE);
}
if (feed->pid)
@ -445,8 +545,10 @@ static void start_children(FFServerStream *feed)
signal(SIGPIPE, SIG_DFL);
execvp(pathname, feed->child_argv);
av_free (pathname);
_exit(1);
}
av_free (pathname);
}
/* open a listening socket */
@ -470,20 +572,22 @@ static int socket_open_listen(struct sockaddr_in *my_addr)
snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)",
ntohs(my_addr->sin_port));
perror (bindmsg);
closesocket(server_fd);
return -1;
goto fail;
}
if (listen (server_fd, 5) < 0) {
perror ("listen");
closesocket(server_fd);
return -1;
goto fail;
}
if (ff_socket_nonblock(server_fd, 1) < 0)
av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
return server_fd;
fail:
closesocket(server_fd);
return -1;
}
/* start all multicast streams */
@ -564,25 +668,21 @@ static int http_server(void)
if (config.http_addr.sin_port) {
server_fd = socket_open_listen(&config.http_addr);
if (server_fd < 0) {
av_free(poll_table);
return -1;
}
if (server_fd < 0)
goto quit;
}
if (config.rtsp_addr.sin_port) {
rtsp_server_fd = socket_open_listen(&config.rtsp_addr);
if (rtsp_server_fd < 0) {
av_free(poll_table);
closesocket(server_fd);
return -1;
goto quit;
}
}
if (!rtsp_server_fd && !server_fd) {
http_log("HTTP and RTSP disabled.\n");
av_free(poll_table);
return -1;
goto quit;
}
http_log("FFserver started.\n");
@ -660,8 +760,7 @@ static int http_server(void)
ret = poll(poll_table, poll_entry - poll_table, delay);
if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
ff_neterrno() != AVERROR(EINTR)) {
av_free(poll_table);
return -1;
goto quit;
}
} while (ret < 0);
@ -695,6 +794,10 @@ static int http_server(void)
new_connection(rtsp_server_fd, 1);
}
}
quit:
av_free(poll_table);
return -1;
}
/* start waiting for a new HTTP/RTSP request */
@ -715,9 +818,12 @@ static void http_send_too_busy_reply(int fd)
"HTTP/1.0 503 Server too busy\r\n"
"Content-type: text/html\r\n"
"\r\n"
"<!DOCTYPE html>\n"
"<html><head><title>Too busy</title></head><body>\r\n"
"<p>The server is too busy to serve your request at this time.</p>\r\n"
"<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
"<p>The server is too busy to serve your request at "
"this time.</p>\r\n"
"<p>The number of current connections is %u, and this "
"exceeds the limit of %u.</p>\r\n"
"</body></html>\r\n",
nb_connections, config.nb_max_connections);
av_assert0(len < sizeof(buffer));
@ -1284,7 +1390,6 @@ static void compute_real_filename(char *filename, int max_size)
char *p;
FFServerStream *stream;
/* compute filename by matching without the file extensions */
av_strlcpy(file1, filename, sizeof(file1));
p = strrchr(file1, '.');
if (p)
@ -1321,6 +1426,7 @@ static int http_parse_request(HTTPContext *c)
char url[1024], *q;
char protocol[32];
char msg[1024];
char *encoded_msg = NULL;
const char *mime_type;
FFServerStream *stream;
int i;
@ -1422,6 +1528,7 @@ static int http_parse_request(HTTPContext *c)
"Location: %s\r\n"
"Content-type: text/html\r\n"
"\r\n"
"<!DOCTYPE html>\n"
"<html><head><title>Moved</title></head><body>\r\n"
"You should be <a href=\"%s\">redirected</a>.\r\n"
"</body></html>\r\n",
@ -1447,7 +1554,7 @@ static int http_parse_request(HTTPContext *c)
if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
current_bandwidth += stream->bandwidth;
/* If already streaming this feed, do not let start another feeder. */
/* If already streaming this feed, do not let another feeder start */
if (stream->feed_opened) {
snprintf(msg, sizeof(msg), "This feed is already being received.");
http_log("Feed '%s' already being received\n", stream->feed_filename);
@ -1461,10 +1568,13 @@ static int http_parse_request(HTTPContext *c)
"HTTP/1.0 503 Server too busy\r\n"
"Content-type: text/html\r\n"
"\r\n"
"<!DOCTYPE html>\n"
"<html><head><title>Too busy</title></head><body>\r\n"
"<p>The server is too busy to serve your request at this time.</p>\r\n"
"<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
"and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
"<p>The server is too busy to serve your request at "
"this time.</p>\r\n"
"<p>The bandwidth being served (including your stream) "
"is %"PRIu64"kbit/s, and this exceeds the limit of "
"%"PRIu64"kbit/s.</p>\r\n"
"</body></html>\r\n",
current_bandwidth, config.max_bandwidth);
q += strlen(q);
@ -1716,20 +1826,27 @@ static int http_parse_request(HTTPContext *c)
send_error:
c->http_error = 404;
q = c->buffer;
htmlstrip(msg);
if (!htmlencode(msg, &encoded_msg)) {
http_log("Could not encode filename '%s' as HTML\n", msg);
}
snprintf(q, c->buffer_size,
"HTTP/1.0 404 Not Found\r\n"
"Content-type: text/html\r\n"
"\r\n"
"<!DOCTYPE html>\n"
"<html>\n"
"<head><title>404 Not Found</title></head>\n"
"<head>\n"
"<meta charset=\"UTF-8\">\n"
"<title>404 Not Found</title>\n"
"</head>\n"
"<body>%s</body>\n"
"</html>\n", msg);
"</html>\n", encoded_msg? encoded_msg : "File not found");
q += strlen(q);
/* prepare output buffer */
c->buffer_ptr = c->buffer;
c->buffer_end = q;
c->state = HTTPSTATE_SEND_HEADER;
av_freep(&encoded_msg);
return 0;
send_status:
compute_status(c);
@ -1761,7 +1878,7 @@ static inline void print_stream_params(AVIOContext *pb, FFServerStream *stream)
stream_no = stream->nb_streams;
avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>"
"type<th>kbits/s<th align=left>codec<th align=left>"
"type<th>kbit/s<th align=left>codec<th align=left>"
"Parameters\n");
for (i = 0; i < stream_no; i++) {
@ -1787,9 +1904,9 @@ static inline void print_stream_params(AVIOContext *pb, FFServerStream *stream)
abort();
}
avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d"
avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%"PRId64
"<td>%s<td>%s\n",
i, type, st->codec->bit_rate/1000,
i, type, (int64_t)st->codec->bit_rate/1000,
codec ? codec->name : "", parameters);
}
@ -1817,6 +1934,7 @@ static void compute_status(HTTPContext *c)
avio_printf(pb, "Pragma: no-cache\r\n");
avio_printf(pb, "\r\n");
avio_printf(pb, "<!DOCTYPE html>\n");
avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
if (c->stream->feed_filename[0])
avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n",
@ -1826,7 +1944,7 @@ static void compute_status(HTTPContext *c)
/* format status */
avio_printf(pb, "<h2>Available Streams</h2>\n");
avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
avio_printf(pb, "<tr><th valign=top>Path<th align=left>Served<br>Conns<th><br>bytes<th valign=top>Format<th>Bit rate<br>kbits/s<th align=left>Video<br>kbits/s<th><br>Codec<th align=left>Audio<br>kbits/s<th><br>Codec<th align=left valign=top>Feed\n");
avio_printf(pb, "<tr><th valign=top>Path<th align=left>Served<br>Conns<th><br>bytes<th valign=top>Format<th>Bit rate<br>kbit/s<th align=left>Video<br>kbit/s<th><br>Codec<th align=left>Audio<br>kbit/s<th><br>Codec<th align=left valign=top>Feed\n");
stream = config.first_stream;
while (stream) {
char sfilename[1024];
@ -1981,7 +2099,7 @@ static void compute_status(HTTPContext *c)
avio_printf(pb, "<table>\n");
avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target "
"bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
"bit/s<th>Actual bit/s<th>Bytes transferred\n");
c1 = first_http_ctx;
i = 0;
while (c1) {
@ -2243,7 +2361,7 @@ static int http_prepare_data(HTTPContext *c)
} else {
int source_index = pkt.stream_index;
/* update first pts if needed */
if (c->first_pts == AV_NOPTS_VALUE) {
if (c->first_pts == AV_NOPTS_VALUE && pkt.dts != AV_NOPTS_VALUE) {
c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
c->start_time = cur_time;
}
@ -2282,14 +2400,16 @@ static int http_prepare_data(HTTPContext *c)
* XXX: need more abstract handling */
if (c->is_packetized) {
/* compute send time and duration */
c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
c->cur_pts -= c->first_pts;
if (pkt.dts != AV_NOPTS_VALUE) {
c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
c->cur_pts -= c->first_pts;
}
c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
/* find RTP context */
c->packet_stream_index = pkt.stream_index;
ctx = c->rtp_ctx[c->packet_stream_index];
if(!ctx) {
av_free_packet(&pkt);
av_packet_unref(&pkt);
break;
}
codec = ctx->streams[0]->codec;
@ -2335,17 +2455,18 @@ static int http_prepare_data(HTTPContext *c)
av_freep(&c->pb_buffer);
len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
ctx->pb = NULL;
c->cur_frame_bytes = len;
c->buffer_ptr = c->pb_buffer;
c->buffer_end = c->pb_buffer + len;
codec->frame_number++;
if (len == 0) {
av_free_packet(&pkt);
av_packet_unref(&pkt);
goto redo;
}
}
av_free_packet(&pkt);
av_packet_unref(&pkt);
}
}
break;
@ -2802,7 +2923,7 @@ static int rtsp_parse_request(HTTPContext *c)
len = sizeof(line) - 1;
memcpy(line, p, len);
line[len] = '\0';
ff_rtsp_parse_line(header, line, NULL, NULL);
ff_rtsp_parse_line(NULL, header, line, NULL, NULL);
p = p1 + 1;
}
@ -3296,6 +3417,7 @@ static int rtp_new_av_stream(HTTPContext *c,
URLContext *h = NULL;
uint8_t *dummy_buf;
int max_packet_size;
void *st_internal;
/* now we can open the relevant output stream */
ctx = avformat_alloc_context();
@ -3303,14 +3425,13 @@ static int rtp_new_av_stream(HTTPContext *c,
return -1;
ctx->oformat = av_guess_format("rtp", NULL, NULL);
st = av_mallocz(sizeof(AVStream));
st = avformat_new_stream(ctx, NULL);
if (!st)
goto fail;
ctx->nb_streams = 1;
ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
if (!ctx->streams)
goto fail;
ctx->streams[0] = st;
av_freep(&st->codec);
av_freep(&st->info);
st_internal = st->internal;
if (!c->stream->feed ||
c->stream->feed == c->stream)
@ -3320,6 +3441,7 @@ static int rtp_new_av_stream(HTTPContext *c,
c->stream->feed->streams[c->stream->feed_streams[stream_index]],
sizeof(AVStream));
st->priv_data = NULL;
st->internal = st_internal;
/* build destination RTP address */
ipaddr = inet_ntoa(dest_addr->sin_addr);
@ -3376,6 +3498,7 @@ static int rtp_new_av_stream(HTTPContext *c,
return -1;
}
avio_close_dyn_buf(ctx->pb, &dummy_buf);
ctx->pb = NULL;
av_free(dummy_buf);
c->rtp_ctx[stream_index] = ctx;
@ -3385,6 +3508,7 @@ static int rtp_new_av_stream(HTTPContext *c,
/********************************************************************/
/* ffserver initialization */
/* FIXME: This code should use avformat_new_stream() */
static AVStream *add_av_stream1(FFServerStream *stream,
AVCodecContext *codec, int copy)
{
@ -3410,6 +3534,7 @@ static AVStream *add_av_stream1(FFServerStream *stream,
fst->codec = codec;
fst->priv_data = av_mallocz(sizeof(FeedData));
fst->internal = av_mallocz(sizeof(*fst->internal));
fst->index = stream->nb_streams;
avpriv_set_pts_info(fst, 33, 1, 90000);
fst->sample_aspect_ratio = codec->sample_aspect_ratio;
@ -3519,72 +3644,110 @@ static void extract_mpeg4_header(AVFormatContext *infile)
}
mpeg4_count--;
}
av_free_packet(&pkt);
av_packet_unref(&pkt);
}
}
/* compute the needed AVStream for each file */
static void build_file_streams(void)
{
FFServerStream *stream, *stream_next;
FFServerStream *stream;
AVFormatContext *infile;
int i, ret;
/* gather all streams */
for(stream = config.first_stream; stream; stream = stream_next) {
AVFormatContext *infile = NULL;
stream_next = stream->next;
if (stream->stream_type == STREAM_TYPE_LIVE &&
!stream->feed) {
/* the stream comes from a file */
/* try to open the file */
/* open stream */
if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
/* specific case : if transport stream output to RTP,
* we use a raw transport stream reader */
av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
}
for(stream = config.first_stream; stream; stream = stream->next) {
infile = NULL;
if (!stream->feed_filename[0]) {
http_log("Unspecified feed file for stream '%s'\n",
stream->filename);
if (stream->stream_type != STREAM_TYPE_LIVE || stream->feed)
continue;
/* the stream comes from a file */
/* try to open the file */
/* open stream */
/* specific case: if transport stream output to RTP,
* we use a raw transport stream reader */
if (stream->fmt && !strcmp(stream->fmt->name, "rtp"))
av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
if (!stream->feed_filename[0]) {
http_log("Unspecified feed file for stream '%s'\n",
stream->filename);
goto fail;
}
http_log("Opening feed file '%s' for stream '%s'\n",
stream->feed_filename, stream->filename);
ret = avformat_open_input(&infile, stream->feed_filename,
stream->ifmt, &stream->in_opts);
if (ret < 0) {
http_log("Could not open '%s': %s\n", stream->feed_filename,
av_err2str(ret));
/* remove stream (no need to spend more time on it) */
fail:
remove_stream(stream);
} else {
/* find all the AVStreams inside and reference them in
* 'stream' */
if (avformat_find_stream_info(infile, NULL) < 0) {
http_log("Could not find codec parameters from '%s'\n",
stream->feed_filename);
avformat_close_input(&infile);
goto fail;
}
extract_mpeg4_header(infile);
http_log("Opening feed file '%s' for stream '%s'\n",
stream->feed_filename, stream->filename);
ret = avformat_open_input(&infile, stream->feed_filename,
stream->ifmt, &stream->in_opts);
if (ret < 0) {
http_log("Could not open '%s': %s\n", stream->feed_filename,
av_err2str(ret));
/* remove stream (no need to spend more time on it) */
fail:
remove_stream(stream);
} else {
/* find all the AVStreams inside and reference them in
* 'stream' */
if (avformat_find_stream_info(infile, NULL) < 0) {
http_log("Could not find codec parameters from '%s'\n",
stream->feed_filename);
avformat_close_input(&infile);
goto fail;
}
extract_mpeg4_header(infile);
for(i=0;i<infile->nb_streams;i++)
add_av_stream1(stream, infile->streams[i]->codec, 1);
for(i=0;i<infile->nb_streams;i++)
add_av_stream1(stream, infile->streams[i]->codec, 1);
avformat_close_input(&infile);
}
avformat_close_input(&infile);
}
}
}
static inline
int check_codec_match(AVCodecContext *ccf, AVCodecContext *ccs, int stream)
{
int matches = 1;
#define CHECK_CODEC(x) (ccf->x != ccs->x)
if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
http_log("Codecs do not match for stream %d\n", stream);
matches = 0;
} else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
http_log("Codec bitrates do not match for stream %d\n", stream);
matches = 0;
} else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
if (CHECK_CODEC(time_base.den) ||
CHECK_CODEC(time_base.num) ||
CHECK_CODEC(width) ||
CHECK_CODEC(height)) {
http_log("Codec width, height or framerate do not match for stream %d\n", stream);
matches = 0;
}
} else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
if (CHECK_CODEC(sample_rate) ||
CHECK_CODEC(channels) ||
CHECK_CODEC(frame_size)) {
http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", stream);
matches = 0;
}
} else {
http_log("Unknown codec type for stream %d\n", stream);
matches = 0;
}
return matches;
}
/* compute the needed AVStream for each feed */
static void build_feed_streams(void)
static int build_feed_streams(void)
{
FFServerStream *stream, *feed;
int i;
int i, fd;
/* gather all streams */
for(stream = config.first_stream; stream; stream = stream->next) {
@ -3595,124 +3758,108 @@ static void build_feed_streams(void)
if (stream->is_feed) {
for(i=0;i<stream->nb_streams;i++)
stream->feed_streams[i] = i;
} else {
/* we handle a stream coming from a feed */
for(i=0;i<stream->nb_streams;i++)
stream->feed_streams[i] = add_av_stream(feed,
stream->streams[i]);
continue;
}
/* we handle a stream coming from a feed */
for(i=0;i<stream->nb_streams;i++)
stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
}
/* create feed files if needed */
for(feed = config.first_feed; feed; feed = feed->next_feed) {
int fd;
if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
/* See if it matches */
AVFormatContext *s = NULL;
int matches = 0;
if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
/* set buffer size */
int ret = ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
if (ret < 0) {
http_log("Failed to set buffer size\n");
exit(1);
/* See if it matches */
if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) < 0) {
http_log("Deleting feed file '%s' as it appears "
"to be corrupt\n",
feed->feed_filename);
goto drop;
}
/* set buffer size */
if (ffio_set_buf_size(s->pb, FFM_PACKET_SIZE) < 0) {
http_log("Failed to set buffer size\n");
avformat_close_input(&s);
goto bail;
}
/* Now see if it matches */
if (s->nb_streams != feed->nb_streams) {
http_log("Deleting feed file '%s' as stream counts "
"differ (%d != %d)\n",
feed->feed_filename, s->nb_streams, feed->nb_streams);
goto drop;
}
matches = 1;
for(i=0;i<s->nb_streams;i++) {
AVStream *sf, *ss;
sf = feed->streams[i];
ss = s->streams[i];
if (sf->index != ss->index || sf->id != ss->id) {
http_log("Index & Id do not match for stream %d (%s)\n",
i, feed->feed_filename);
matches = 0;
break;
}
/* Now see if it matches */
if (s->nb_streams == feed->nb_streams) {
matches = 1;
for(i=0;i<s->nb_streams;i++) {
AVStream *sf, *ss;
sf = feed->streams[i];
ss = s->streams[i];
if (sf->index != ss->index ||
sf->id != ss->id) {
http_log("Index & Id do not match for stream %d (%s)\n",
i, feed->feed_filename);
matches = 0;
} else {
AVCodecContext *ccf, *ccs;
ccf = sf->codec;
ccs = ss->codec;
#define CHECK_CODEC(x) (ccf->x != ccs->x)
if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
http_log("Codecs do not match for stream %d\n", i);
matches = 0;
} else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
http_log("Codec bitrates do not match for stream %d\n", i);
matches = 0;
} else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
if (CHECK_CODEC(time_base.den) ||
CHECK_CODEC(time_base.num) ||
CHECK_CODEC(width) ||
CHECK_CODEC(height)) {
http_log("Codec width, height and framerate do not match for stream %d\n", i);
matches = 0;
}
} else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
if (CHECK_CODEC(sample_rate) ||
CHECK_CODEC(channels) ||
CHECK_CODEC(frame_size)) {
http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
matches = 0;
}
} else {
http_log("Unknown codec type\n");
matches = 0;
}
}
if (!matches)
break;
}
} else
http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
feed->feed_filename, s->nb_streams, feed->nb_streams);
matches = check_codec_match (sf->codec, ss->codec, i);
if (!matches)
break;
}
drop:
if (s)
avformat_close_input(&s);
} else
http_log("Deleting feed file '%s' as it appears to be corrupt\n",
feed->feed_filename);
if (!matches) {
if (feed->readonly) {
http_log("Unable to delete feed file '%s' as it is marked readonly\n",
feed->feed_filename);
exit(1);
http_log("Unable to delete read-only feed file '%s'\n",
feed->feed_filename);
goto bail;
}
unlink(feed->feed_filename);
}
}
if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
AVFormatContext *s = avformat_alloc_context();
if (!s) {
http_log("Failed to allocate context\n");
exit(1);
goto bail;
}
if (feed->readonly) {
http_log("Unable to create feed file '%s' as it is marked readonly\n",
feed->feed_filename);
exit(1);
http_log("Unable to create feed file '%s' as it is "
"marked readonly\n",
feed->feed_filename);
avformat_free_context(s);
goto bail;
}
/* only write the header of the ffm file */
if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
http_log("Could not open output feed file '%s'\n",
feed->feed_filename);
exit(1);
avformat_free_context(s);
goto bail;
}
s->oformat = feed->fmt;
s->nb_streams = feed->nb_streams;
s->streams = feed->streams;
if (avformat_write_header(s, NULL) < 0) {
http_log("Container doesn't support the required parameters\n");
exit(1);
avio_closep(&s->pb);
avformat_free_context(s);
goto bail;
}
/* XXX: need better API */
av_freep(&s->priv_data);
@ -3721,15 +3868,17 @@ static void build_feed_streams(void)
s->nb_streams = 0;
avformat_free_context(s);
}
/* get feed size and write index */
fd = open(feed->feed_filename, O_RDONLY);
if (fd < 0) {
http_log("Could not open output feed file '%s'\n",
feed->feed_filename);
exit(1);
goto bail;
}
feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
feed->feed_write_index = FFMAX(ffm_read_write_index(fd),
FFM_PACKET_SIZE);
feed->feed_size = lseek(fd, 0, SEEK_END);
/* ensure that we do not wrap before the end of file */
if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
@ -3737,6 +3886,10 @@ static void build_feed_streams(void)
close(fd);
}
return 0;
bail:
return -1;
}
/* compute the bandwidth used by each stream */
@ -3766,7 +3919,8 @@ static void compute_bandwidth(void)
static void handle_child_exit(int sig)
{
pid_t pid;
int status, uptime;
int status;
time_t uptime;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
FFServerStream *feed;
@ -3778,8 +3932,9 @@ static void handle_child_exit(int sig)
uptime = time(0) - feed->pid_start;
feed->pid = 0;
fprintf(stderr,
"%s: Pid %"PRId64" exited with status %d after %d seconds\n",
feed->filename, (int64_t) pid, status, uptime);
"%s: Pid %"PRId64" exited with status %d after %"PRId64" "
"seconds\n",
feed->filename, (int64_t) pid, status, (int64_t)uptime);
if (uptime < 30)
/* Turn off any more restarts */
@ -3815,7 +3970,9 @@ static const OptionDef options[] = {
int main(int argc, char **argv)
{
struct sigaction sigact = { { 0 } };
int ret = 0;
int cfg_parsed;
int ret = EXIT_FAILURE;
config.filename = av_strdup("/etc/ffserver.conf");
@ -3837,12 +3994,11 @@ int main(int argc, char **argv)
sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
sigaction(SIGCHLD, &sigact, 0);
if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
if ((cfg_parsed = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
fprintf(stderr, "Error reading configuration file '%s': %s\n",
config.filename, av_err2str(ret));
exit(1);
config.filename, av_err2str(cfg_parsed));
goto bail;
}
av_freep(&config.filename);
/* open log file if needed */
if (config.logfilename[0] != '\0') {
@ -3855,7 +4011,10 @@ int main(int argc, char **argv)
build_file_streams();
build_feed_streams();
if (build_feed_streams() < 0) {
http_log("Could not setup feed streams\n");
goto bail;
}
compute_bandwidth();
@ -3864,8 +4023,13 @@ int main(int argc, char **argv)
if (http_server() < 0) {
http_log("Could not start server\n");
exit(1);
goto bail;
}
return 0;
ret=EXIT_SUCCESS;
bail:
av_freep (&config.filename);
avformat_network_deinit();
return ret;
}

View File

@ -42,8 +42,8 @@ static void report_config_error(const char *filename, int line_num,
int log_level, int *errors, const char *fmt,
...);
#define ERROR(...) report_config_error(config->filename, config->line_num,\
AV_LOG_ERROR, &config->errors, __VA_ARGS__)
#define ERROR(...) report_config_error(config->filename, config->line_num,\
AV_LOG_ERROR, &config->errors, __VA_ARGS__)
#define WARNING(...) report_config_error(config->filename, config->line_num,\
AV_LOG_WARNING, &config->warnings, __VA_ARGS__)
@ -116,7 +116,8 @@ void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream* feed,
{
char arg[1024];
FFServerIPAddressACL acl;
int errors = 0;
FFServerIPAddressACL *nacl;
FFServerIPAddressACL **naclp;
ffserver_get_arg(arg, sizeof(arg), &p);
if (av_strcasecmp(arg, "allow") == 0)
@ -126,7 +127,7 @@ void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream* feed,
else {
fprintf(stderr, "%s:%d: ACL action '%s' should be ALLOW or DENY.\n",
filename, line_num, arg);
errors++;
goto bail;
}
ffserver_get_arg(arg, sizeof(arg), &p);
@ -135,9 +136,10 @@ void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream* feed,
fprintf(stderr,
"%s:%d: ACL refers to invalid host or IP address '%s'\n",
filename, line_num, arg);
errors++;
} else
acl.last = acl.first;
goto bail;
}
acl.last = acl.first;
ffserver_get_arg(arg, sizeof(arg), &p);
@ -146,37 +148,37 @@ void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream* feed,
fprintf(stderr,
"%s:%d: ACL refers to invalid host or IP address '%s'\n",
filename, line_num, arg);
errors++;
goto bail;
}
}
if (!errors) {
FFServerIPAddressACL *nacl = av_mallocz(sizeof(*nacl));
FFServerIPAddressACL **naclp = 0;
nacl = av_mallocz(sizeof(*nacl));
naclp = 0;
acl.next = 0;
*nacl = acl;
acl.next = 0;
*nacl = acl;
if (stream)
naclp = &stream->acl;
else if (feed)
naclp = &feed->acl;
else if (ext_acl)
naclp = &ext_acl;
else {
fprintf(stderr, "%s:%d: ACL found not in <Stream> or <Feed>\n",
filename, line_num);
errors++;
}
if (stream)
naclp = &stream->acl;
else if (feed)
naclp = &feed->acl;
else if (ext_acl)
naclp = &ext_acl;
else
fprintf(stderr, "%s:%d: ACL found not in <Stream> or <Feed>\n",
filename, line_num);
if (naclp) {
while (*naclp)
naclp = &(*naclp)->next;
if (naclp) {
while (*naclp)
naclp = &(*naclp)->next;
*naclp = nacl;
} else
av_free(nacl);
bail:
return;
*naclp = nacl;
} else
av_free(nacl);
}
}
/* add a codec and set the default parameters */
@ -458,7 +460,7 @@ static int ffserver_set_int_param(int *dest, const char *value, int factor,
if (tmp < min || tmp > max)
goto error;
if (factor) {
if (FFABS(tmp) > INT_MAX / FFABS(factor))
if (tmp == INT_MIN || FFABS(tmp) > INT_MAX / FFABS(factor))
goto error;
tmp *= factor;
}
@ -683,8 +685,8 @@ static int ffserver_parse_config_global(FFServerConfig *config, const char *cmd,
return 0;
}
static int ffserver_parse_config_feed(FFServerConfig *config, const char *cmd, const char **p,
FFServerStream **pfeed)
static int ffserver_parse_config_feed(FFServerConfig *config, const char *cmd,
const char **p, FFServerStream **pfeed)
{
FFServerStream *feed;
char arg[1024];
@ -791,7 +793,8 @@ static int ffserver_parse_config_feed(FFServerConfig *config, const char *cmd, c
return 0;
}
static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd, const char **p,
static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
const char **p,
FFServerStream **pstream)
{
char arg[1024], arg2[1024];

View File

@ -3,11 +3,12 @@ include $(SUBDIR)../config.mak
NAME = avcodec
HEADERS = avcodec.h \
avdct.h \
avfft.h \
dv_profile.h \
d3d11va.h \
dirac.h \
dxva2.h \
old_codec_ids.h \
qsv.h \
vaapi.h \
vda.h \
@ -25,11 +26,14 @@ OBJS = allcodecs.o \
bitstream.o \
bitstream_filter.o \
codec_desc.o \
d3d11va.o \
dirac.o \
dv_profile.o \
imgconvert.o \
mathtables.o \
options.o \
parser.o \
profiles.o \
qsv_api.o \
raw.o \
resample.o \
@ -80,6 +84,7 @@ OBJS-$(CONFIG_LLAUDDSP) += lossless_audiodsp.o
OBJS-$(CONFIG_LLVIDDSP) += lossless_videodsp.o
OBJS-$(CONFIG_LPC) += lpc.o
OBJS-$(CONFIG_LSP) += lsp.o
OBJS-$(CONFIG_LZF) += lzf.o
OBJS-$(CONFIG_MDCT) += mdct_fixed.o mdct_float.o mdct_fixed_32.o
OBJS-$(CONFIG_ME_CMP) += me_cmp.o
OBJS-$(CONFIG_MPEG_ER) += mpeg_er.o
@ -134,6 +139,7 @@ OBJS-$(CONFIG_AAC_ENCODER) += aacenc.o aaccoder.o aacenctab.o \
aacpsy.o aactab.o \
aacenc_is.o \
aacenc_tns.o \
aacenc_ltp.o \
aacenc_pred.o \
psymodel.o mpeg4audio.o kbdwin.o
OBJS-$(CONFIG_AASC_DECODER) += aasc.o msrledec.o
@ -143,7 +149,7 @@ OBJS-$(CONFIG_AC3_ENCODER) += ac3enc_float.o ac3enc.o ac3tab.o \
ac3.o kbdwin.o
OBJS-$(CONFIG_AC3_FIXED_ENCODER) += ac3enc_fixed.o ac3enc.o ac3tab.o ac3.o
OBJS-$(CONFIG_AIC_DECODER) += aic.o
OBJS-$(CONFIG_ALAC_DECODER) += alac.o alac_data.o
OBJS-$(CONFIG_ALAC_DECODER) += alac.o alac_data.o alacdsp.o
OBJS-$(CONFIG_ALAC_ENCODER) += alacenc.o alac_data.o
OBJS-$(CONFIG_ALIAS_PIX_DECODER) += aliaspixdec.o
OBJS-$(CONFIG_ALIAS_PIX_ENCODER) += aliaspixenc.o
@ -204,6 +210,7 @@ OBJS-$(CONFIG_CAVS_DECODER) += cavs.o cavsdec.o cavsdsp.o \
OBJS-$(CONFIG_CCAPTION_DECODER) += ccaption_dec.o
OBJS-$(CONFIG_CDGRAPHICS_DECODER) += cdgraphics.o
OBJS-$(CONFIG_CDXL_DECODER) += cdxl.o
OBJS-$(CONFIG_CFHD_DECODER) += cfhd.o cfhddata.o
OBJS-$(CONFIG_CINEPAK_DECODER) += cinepak.o
OBJS-$(CONFIG_CINEPAK_ENCODER) += cinepakenc.o elbg.o
OBJS-$(CONFIG_CLJR_DECODER) += cljrdec.o
@ -215,12 +222,12 @@ OBJS-$(CONFIG_COMFORTNOISE_ENCODER) += cngenc.o
OBJS-$(CONFIG_CPIA_DECODER) += cpia.o
OBJS-$(CONFIG_CSCD_DECODER) += cscd.o
OBJS-$(CONFIG_CYUV_DECODER) += cyuv.o
OBJS-$(CONFIG_DCA_DECODER) += dcadec.o dca.o dcadsp.o \
dcadata.o dca_exss.o \
dca_xll.o synth_filter.o
OBJS-$(CONFIG_DCA_DECODER) += dcadec.o dca.o dcadata.o \
dca_core.o dca_exss.o dca_xll.o \
dcadsp.o dcadct.o synth_filter.o
OBJS-$(CONFIG_DCA_ENCODER) += dcaenc.o dca.o dcadata.o
OBJS-$(CONFIG_DDS_DECODER) += dds.o
OBJS-$(CONFIG_DIRAC_DECODER) += diracdec.o dirac.o diracdsp.o \
OBJS-$(CONFIG_DIRAC_DECODER) += diracdec.o dirac.o diracdsp.o diractab.o \
dirac_arith.o mpeg12data.o dirac_dwt.o
OBJS-$(CONFIG_DFA_DECODER) += dfa.o
OBJS-$(CONFIG_DNXHD_DECODER) += dnxhddec.o dnxhddata.o
@ -238,10 +245,12 @@ OBJS-$(CONFIG_DVBSUB_DECODER) += dvbsubdec.o
OBJS-$(CONFIG_DVBSUB_ENCODER) += dvbsub.o
OBJS-$(CONFIG_DVDSUB_DECODER) += dvdsubdec.o
OBJS-$(CONFIG_DVDSUB_ENCODER) += dvdsubenc.o
OBJS-$(CONFIG_DVAUDIO_DECODER) += dvaudiodec.o
OBJS-$(CONFIG_DVVIDEO_DECODER) += dvdec.o dv.o dvdata.o
OBJS-$(CONFIG_DVVIDEO_ENCODER) += dvenc.o dv.o dvdata.o
OBJS-$(CONFIG_DXA_DECODER) += dxa.o
OBJS-$(CONFIG_DXTORY_DECODER) += dxtory.o
OBJS-$(CONFIG_DXV_DECODER) += dxv.o
OBJS-$(CONFIG_EAC3_DECODER) += eac3_data.o
OBJS-$(CONFIG_EAC3_ENCODER) += eac3enc.o eac3_data.o
OBJS-$(CONFIG_EACMV_DECODER) += eacmv.o
@ -272,9 +281,10 @@ OBJS-$(CONFIG_FOURXM_DECODER) += 4xm.o
OBJS-$(CONFIG_FRAPS_DECODER) += fraps.o
OBJS-$(CONFIG_FRWU_DECODER) += frwu.o
OBJS-$(CONFIG_G2M_DECODER) += g2meet.o elsdec.o
OBJS-$(CONFIG_G723_1_DECODER) += g723_1.o acelp_vectors.o \
celp_filters.o celp_math.o
OBJS-$(CONFIG_G723_1_ENCODER) += g723_1.o acelp_vectors.o celp_math.o
OBJS-$(CONFIG_G723_1_DECODER) += g723_1dec.o g723_1.o \
acelp_vectors.o celp_filters.o celp_math.o
OBJS-$(CONFIG_G723_1_ENCODER) += g723_1enc.o g723_1.o \
acelp_vectors.o celp_filters.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
@ -310,13 +320,13 @@ OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o huffyuvdec.o
OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o huffyuvenc.o
OBJS-$(CONFIG_IDCIN_DECODER) += idcinvideo.o
OBJS-$(CONFIG_IDF_DECODER) += bintext.o cga_data.o
OBJS-$(CONFIG_IFF_BYTERUN1_DECODER) += iff.o
OBJS-$(CONFIG_IFF_ILBM_DECODER) += iff.o
OBJS-$(CONFIG_IMC_DECODER) += imc.o
OBJS-$(CONFIG_INDEO2_DECODER) += indeo2.o
OBJS-$(CONFIG_INDEO3_DECODER) += indeo3.o
OBJS-$(CONFIG_INDEO4_DECODER) += indeo4.o ivi.o
OBJS-$(CONFIG_INDEO5_DECODER) += indeo5.o ivi.o
OBJS-$(CONFIG_INTERPLAY_ACM_DECODER) += interplayacm.o
OBJS-$(CONFIG_INTERPLAY_DPCM_DECODER) += dpcm.o
OBJS-$(CONFIG_INTERPLAY_VIDEO_DECODER) += interplayvideo.o
OBJS-$(CONFIG_JACOSUB_DECODER) += jacosubdec.o ass.o
@ -368,6 +378,7 @@ 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_MPEG2_MMAL_DECODER) += mmaldec.o
OBJS-$(CONFIG_MPEG2_QSV_DECODER) += qsvdec_mpeg2.o
OBJS-$(CONFIG_MPEG2_QSV_ENCODER) += qsvenc_mpeg2.o
OBJS-$(CONFIG_MPEG4_DECODER) += xvididct.o
@ -444,16 +455,19 @@ OBJS-$(CONFIG_ROQ_ENCODER) += roqvideoenc.o roqvideo.o elbg.o
OBJS-$(CONFIG_ROQ_DPCM_DECODER) += dpcm.o
OBJS-$(CONFIG_ROQ_DPCM_ENCODER) += roqaudioenc.o
OBJS-$(CONFIG_RPZA_DECODER) += rpza.o
OBJS-$(CONFIG_RSCC_DECODER) += rscc.o
OBJS-$(CONFIG_RV10_DECODER) += rv10.o
OBJS-$(CONFIG_RV10_ENCODER) += rv10enc.o
OBJS-$(CONFIG_RV20_DECODER) += rv10.o
OBJS-$(CONFIG_RV20_ENCODER) += rv20enc.o
OBJS-$(CONFIG_RV30_DECODER) += rv30.o rv34.o rv30dsp.o
OBJS-$(CONFIG_RV40_DECODER) += rv40.o rv34.o rv40dsp.o
OBJS-$(CONFIG_SAMI_DECODER) += samidec.o ass.o
OBJS-$(CONFIG_SAMI_DECODER) += samidec.o ass.o htmlsubtitles.o
OBJS-$(CONFIG_S302M_DECODER) += s302m.o
OBJS-$(CONFIG_S302M_ENCODER) += s302menc.o
OBJS-$(CONFIG_SANM_DECODER) += sanm.o
OBJS-$(CONFIG_SCREENPRESSO_DECODER) += screenpresso.o
OBJS-$(CONFIG_SDX2_DPCM_DECODER) += dpcm.o
OBJS-$(CONFIG_SGI_DECODER) += sgidec.o
OBJS-$(CONFIG_SGI_ENCODER) += sgienc.o rle.o
OBJS-$(CONFIG_SGIRLE_DECODER) += sgirledec.o
@ -474,10 +488,10 @@ OBJS-$(CONFIG_SONIC_DECODER) += sonic.o
OBJS-$(CONFIG_SONIC_ENCODER) += sonic.o
OBJS-$(CONFIG_SONIC_LS_ENCODER) += sonic.o
OBJS-$(CONFIG_SP5X_DECODER) += sp5xdec.o
OBJS-$(CONFIG_SRT_DECODER) += srtdec.o ass.o
OBJS-$(CONFIG_SRT_DECODER) += srtdec.o ass.o htmlsubtitles.o
OBJS-$(CONFIG_SRT_ENCODER) += srtenc.o ass_split.o
OBJS-$(CONFIG_STL_DECODER) += textdec.o ass.o
OBJS-$(CONFIG_SUBRIP_DECODER) += srtdec.o ass.o
OBJS-$(CONFIG_SUBRIP_DECODER) += srtdec.o ass.o htmlsubtitles.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
@ -488,7 +502,8 @@ OBJS-$(CONFIG_SVQ1_ENCODER) += svq1enc.o svq1.o \
h263.o ituh263enc.o
OBJS-$(CONFIG_SVQ3_DECODER) += svq3.o svq13.o mpegutils.o
OBJS-$(CONFIG_TEXT_DECODER) += textdec.o ass.o
OBJS-$(CONFIG_TAK_DECODER) += takdec.o tak.o
OBJS-$(CONFIG_TEXT_ENCODER) += srtenc.o ass_split.o
OBJS-$(CONFIG_TAK_DECODER) += takdec.o tak.o takdsp.o
OBJS-$(CONFIG_TARGA_DECODER) += targa.o
OBJS-$(CONFIG_TARGA_ENCODER) += targaenc.o rle.o
OBJS-$(CONFIG_TARGA_Y216_DECODER) += targa_y216dec.o
@ -526,7 +541,9 @@ OBJS-$(CONFIG_VC1_DECODER) += vc1dec.o vc1_block.o vc1_loopfilter.o
vc1dsp.o \
msmpeg4dec.o msmpeg4.o msmpeg4data.o \
wmv2dsp.o
OBJS-$(CONFIG_VC1_MMAL_DECODER) += mmaldec.o
OBJS-$(CONFIG_VC1_QSV_DECODER) += qsvdec_vc1.o
OBJS-$(CONFIG_VC2_ENCODER) += vc2enc.o vc2enc_dwt.o diractab.o
OBJS-$(CONFIG_VCR1_DECODER) += vcr1.o
OBJS-$(CONFIG_VMDAUDIO_DECODER) += vmdaudio.o
OBJS-$(CONFIG_VMDVIDEO_DECODER) += vmdvideo.o
@ -547,8 +564,7 @@ OBJS-$(CONFIG_VPLAYER_DECODER) += textdec.o ass.o
OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o
OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o
OBJS-$(CONFIG_WAVPACK_ENCODER) += wavpackenc.o
OBJS-$(CONFIG_WEBP_DECODER) += vp8.o vp8dsp.o vp56rac.o
OBJS-$(CONFIG_WEBP_DECODER) += webp.o exif.o tiff_common.o
OBJS-$(CONFIG_WEBP_DECODER) += webp.o
OBJS-$(CONFIG_WEBVTT_DECODER) += webvttdec.o ass.o
OBJS-$(CONFIG_WEBVTT_ENCODER) += webvttenc.o ass_split.o
OBJS-$(CONFIG_WMALOSSLESS_DECODER) += wmalosslessdec.o wma_common.o
@ -568,6 +584,7 @@ OBJS-$(CONFIG_WMV2_ENCODER) += wmv2enc.o wmv2.o \
msmpeg4.o msmpeg4enc.o msmpeg4data.o
OBJS-$(CONFIG_WNV1_DECODER) += wnv1.o
OBJS-$(CONFIG_WS_SND1_DECODER) += ws-snd1.o
OBJS-$(CONFIG_WRAPPED_AVFRAME_ENCODER) += wrapped_avframe.o
OBJS-$(CONFIG_XAN_DPCM_DECODER) += dpcm.o
OBJS-$(CONFIG_XAN_WC3_DECODER) += xan.o
OBJS-$(CONFIG_XAN_WC4_DECODER) += xxan.o
@ -577,6 +594,8 @@ 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_XMA1_DECODER) += wmaprodec.o wma.o wma_common.o
OBJS-$(CONFIG_XMA2_DECODER) += wmaprodec.o wma.o wma_common.o
OBJS-$(CONFIG_XSUB_DECODER) += xsubdec.o
OBJS-$(CONFIG_XSUB_ENCODER) += xsubenc.o
OBJS-$(CONFIG_XWD_DECODER) += xwddec.o
@ -654,6 +673,7 @@ 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_AICA_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
@ -684,6 +704,7 @@ OBJS-$(CONFIG_ADPCM_IMA_WAV_ENCODER) += adpcmenc.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_IMA_WS_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_MS_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_MS_ENCODER) += adpcmenc.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_PSX_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_SBPRO_2_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_SBPRO_3_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_SBPRO_4_DECODER) += adpcm.o adpcm_data.o
@ -694,7 +715,6 @@ OBJS-$(CONFIG_ADPCM_VIMA_DECODER) += vima.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_XA_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_YAMAHA_DECODER) += adpcm.o adpcm_data.o
OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER) += adpcmenc.o adpcm_data.o
OBJS-$(CONFIG_VIMA_DECODER) += vima.o adpcm_data.o
# hardware accelerators
OBJS-$(CONFIG_D3D11VA) += dxva2.o
@ -705,7 +725,6 @@ OBJS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.o
OBJS-$(CONFIG_VDPAU) += vdpau.o
OBJS-$(CONFIG_H263_VAAPI_HWACCEL) += vaapi_mpeg4.o
OBJS-$(CONFIG_H263_VDPAU_HWACCEL) += vdpau_mpeg4.o
OBJS-$(CONFIG_H263_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o
OBJS-$(CONFIG_H264_D3D11VA_HWACCEL) += dxva2_h264.o
OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o
@ -733,9 +752,13 @@ OBJS-$(CONFIG_VC1_D3D11VA_HWACCEL) += dxva2_vc1.o
OBJS-$(CONFIG_VC1_DXVA2_HWACCEL) += dxva2_vc1.o
OBJS-$(CONFIG_VC1_VAAPI_HWACCEL) += vaapi_vc1.o
OBJS-$(CONFIG_VC1_VDPAU_HWACCEL) += vdpau_vc1.o
OBJS-$(CONFIG_VP9_D3D11VA_HWACCEL) += dxva2_vp9.o
OBJS-$(CONFIG_VP9_DXVA2_HWACCEL) += dxva2_vp9.o
OBJS-$(CONFIG_VP9_VAAPI_HWACCEL) += vaapi_vp9.o
# libavformat dependencies
OBJS-$(CONFIG_ADTS_MUXER) += mpeg4audio.o
OBJS-$(CONFIG_AVI_DEMUXER) += mpeg4audio.o mpegaudiodata.o
OBJS-$(CONFIG_CAF_DEMUXER) += mpeg4audio.o mpegaudiodata.o \
ac3tab.o
OBJS-$(CONFIG_FLAC_DEMUXER) += flac.o flacdata.o vorbis_data.o
@ -777,7 +800,6 @@ OBJS-$(CONFIG_WTV_DEMUXER) += mpeg4audio.o mpegaudiodata.o
OBJS-$(CONFIG_ELBG_FILTER) += elbg.o
# external codec libraries
OBJS-$(CONFIG_LIBAACPLUS_ENCODER) += libaacplus.o
OBJS-$(CONFIG_LIBCELT_DECODER) += libcelt_dec.o
OBJS-$(CONFIG_LIBDCADEC_DECODER) += libdcadec.o dca.o
OBJS-$(CONFIG_LIBFAAC_ENCODER) += libfaac.o
@ -808,12 +830,10 @@ OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER) += libschroedingerenc.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_DECODER) += libvorbisdec.o
OBJS-$(CONFIG_LIBVORBIS_ENCODER) += libvorbisenc.o \
@ -846,6 +866,7 @@ OBJS-$(CONFIG_DCA_PARSER) += dca_parser.o dca.o
OBJS-$(CONFIG_DIRAC_PARSER) += dirac_parser.o
OBJS-$(CONFIG_DNXHD_PARSER) += dnxhd_parser.o
OBJS-$(CONFIG_DPX_PARSER) += dpx_parser.o
OBJS-$(CONFIG_DVAUDIO_PARSER) += dvaudio_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
@ -907,17 +928,20 @@ SLIBOBJS-$(HAVE_GNU_WINDRES) += avcodecres.o
SKIPHEADERS += %_tablegen.h \
%_tables.h \
aac_tablegen_decl.h \
fft-internal.h \
old_codec_ids.h \
tableprint.h \
tableprint_vlc.h \
aaccoder_twoloop.h \
aaccoder_trellis.h \
aacenc_quantization.h \
aacenc_quantization_misc.h \
$(ARCH)/vp56_arith.h \
SKIPHEADERS-$(CONFIG_D3D11VA) += d3d11va.h dxva2_internal.h
SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h
SKIPHEADERS-$(CONFIG_LIBSCHROEDINGER) += libschroedinger.h
SKIPHEADERS-$(CONFIG_LIBUTVIDEO) += libutvideo.h
SKIPHEADERS-$(CONFIG_LIBVPX) += libvpx.h
SKIPHEADERS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.h
SKIPHEADERS-$(CONFIG_QSV) += qsv.h qsv_internal.h
SKIPHEADERS-$(CONFIG_QSVDEC) += qsvdec.h
@ -947,16 +971,11 @@ TESTOBJS = dctref.o
TOOLS = fourcc2pixfmt
HOSTPROGS = aac_tablegen \
aacps_tablegen \
HOSTPROGS = aacps_tablegen \
aacps_fixed_tablegen \
aacsbr_tablegen \
aacsbr_fixed_tablegen \
cabac_tablegen \
cbrt_tablegen \
cbrt_fixed_tablegen \
cos_tablegen \
dsd_tablegen \
dv_tablegen \
motionpixels_tablegen \
mpegaudio_tablegen \
@ -982,8 +1001,8 @@ else
$(SUBDIR)%_tablegen$(HOSTEXESUF): HOSTCFLAGS += -DCONFIG_SMALL=0
endif
GEN_HEADERS = cabac_tables.h cbrt_tables.h cbrt_fixed_tables.h aacps_tables.h aacps_fixed_tables.h aacsbr_tables.h \
aacsbr_fixed_tables.h aac_tables.h dsd_tables.h dv_tables.h \
GEN_HEADERS = cbrt_tables.h cbrt_fixed_tables.h aacps_tables.h aacps_fixed_tables.h \
dv_tables.h \
sinewin_tables.h sinewin_fixed_tables.h mpegaudio_tables.h motionpixels_tables.h \
pcm_tables.h qdm2_tables.h
GEN_HEADERS := $(addprefix $(SUBDIR), $(GEN_HEADERS))
@ -996,12 +1015,7 @@ $(SUBDIR)aacdec.o: $(SUBDIR)cbrt_tables.h
$(SUBDIR)aacdec_fixed.o: $(SUBDIR)cbrt_fixed_tables.h
$(SUBDIR)aacps_float.o: $(SUBDIR)aacps_tables.h
$(SUBDIR)aacps_fixed.o: $(SUBDIR)aacps_fixed_tables.h
$(SUBDIR)aacsbr.o: $(SUBDIR)aacsbr_tables.h
$(SUBDIR)aacsbr_fixed.o: $(SUBDIR)aacsbr_fixed_tables.h
$(SUBDIR)aactab.o: $(SUBDIR)aac_tables.h
$(SUBDIR)aactab_fixed.o: $(SUBDIR)aac_fixed_tables.h
$(SUBDIR)cabac.o: $(SUBDIR)cabac_tables.h
$(SUBDIR)dsddec.o: $(SUBDIR)dsd_tables.h
$(SUBDIR)dvenc.o: $(SUBDIR)dv_tables.h
$(SUBDIR)sinewin.o: $(SUBDIR)sinewin_tables.h
$(SUBDIR)sinewin_fixed.o: $(SUBDIR)sinewin_fixed_tables.h

View File

@ -151,6 +151,8 @@ typedef struct PredictorState {
#define SCALE_MAX_DIFF 60 ///< maximum scalefactor difference allowed by standard
#define SCALE_DIFF_ZERO 60 ///< codebook index corresponding to zero scalefactor indices difference
#define POW_SF2_ZERO 200 ///< ff_aac_pow2sf_tab index corresponding to pow(2, 0);
#define NOISE_PRE 256 ///< preamble for NOISE_BT, put in bitstream with the first noise band
#define NOISE_PRE_BITS 9 ///< length of preamble
#define NOISE_OFFSET 90 ///< subtracted from global gain, used as offset for the preamble
@ -161,6 +163,7 @@ typedef struct PredictorState {
typedef struct LongTermPrediction {
int8_t present;
int16_t lag;
int coef_idx;
INTFLOAT coef;
int8_t used[MAX_LTP_LONG_SFB];
} LongTermPrediction;
@ -252,6 +255,7 @@ typedef struct SingleChannelElement {
INTFLOAT sf[120]; ///< scalefactors
int sf_idx[128]; ///< scalefactor indices (used by encoder)
uint8_t zeroes[128]; ///< band is not coded (used by encoder)
uint8_t can_pns[128]; ///< band is allowed to PNS (informative)
float is_ener[128]; ///< Intensity stereo pos (used by encoder)
float pns_ener[128]; ///< Noise energy values (used by encoder)
DECLARE_ALIGNED(32, INTFLOAT, pcoeffs)[1024]; ///< coefficients for IMDCT, pristine
@ -259,6 +263,7 @@ typedef struct SingleChannelElement {
DECLARE_ALIGNED(32, INTFLOAT, saved)[1536]; ///< overlap
DECLARE_ALIGNED(32, INTFLOAT, ret_buf)[2048]; ///< PCM output buffer
DECLARE_ALIGNED(16, INTFLOAT, ltp_state)[3072]; ///< time signal for LTP
DECLARE_ALIGNED(32, AAC_FLOAT, lcoeffs)[1024]; ///< MDCT of LTP coefficients (used by encoder)
DECLARE_ALIGNED(32, AAC_FLOAT, prcoeffs)[1024]; ///< Main prediction coefs (used by encoder)
PredictorState predictor_state[MAX_PREDICTORS];
INTFLOAT *ret; ///< PCM output

View File

@ -84,14 +84,6 @@ get_next:
avctx->sample_rate = s->sample_rate;
/* (E-)AC-3: allow downmixing to stereo or mono */
#if FF_API_REQUEST_CHANNELS
FF_DISABLE_DEPRECATION_WARNINGS
if (avctx->request_channels == 1)
avctx->request_channel_layout = AV_CH_LAYOUT_MONO;
else if (avctx->request_channels == 2)
avctx->request_channel_layout = AV_CH_LAYOUT_STEREO;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
if (s->channels > 1 &&
avctx->request_channel_layout == AV_CH_LAYOUT_MONO) {
avctx->channels = 1;

View File

@ -34,11 +34,11 @@
#define AAC_RENAME(x) x ## _fixed
#define AAC_RENAME_32(x) x ## _fixed_32
#define INTFLOAT int
#define INT64FLOAT int64_t
#define SHORTFLOAT int16_t
#define AAC_FLOAT SoftFloat
#define AAC_SIGNE int
typedef int INTFLOAT;
typedef int64_t INT64FLOAT;
typedef int16_t SHORTFLOAT;
typedef SoftFloat AAC_FLOAT;
typedef int AAC_SIGNE;
#define FIXR(a) ((int)((a) * 1 + 0.5))
#define FIXR10(a) ((int)((a) * 1024.0 + 0.5))
#define Q23(a) (int)((a) * 8388608.0 + 0.5)
@ -82,11 +82,11 @@
#define AAC_RENAME(x) x
#define AAC_RENAME_32(x) x
#define INTFLOAT float
#define INT64FLOAT float
#define SHORTFLOAT float
#define AAC_FLOAT float
#define AAC_SIGNE unsigned
typedef float INTFLOAT;
typedef float INT64FLOAT;
typedef float SHORTFLOAT;
typedef float AAC_FLOAT;
typedef unsigned AAC_SIGNE;
#define FIXR(x) ((float)(x))
#define FIXR10(x) ((float)(x))
#define Q23(x) x

View File

@ -1,38 +0,0 @@
/*
* Header file for hardcoded AAC tables
*
* Copyright (c) 2010 Alex Converse <alex.converse@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 AVCODEC_AAC_TABLEGEN_DECL_H
#define AVCODEC_AAC_TABLEGEN_DECL_H
#define POW_SF2_ZERO 200 ///< ff_aac_pow2sf_tab index corresponding to pow(2, 0);
#if CONFIG_HARDCODED_TABLES
#define ff_aac_tableinit()
extern const float ff_aac_pow2sf_tab[428];
extern const float ff_aac_pow34sf_tab[428];
#else
void ff_aac_tableinit(void);
extern float ff_aac_pow2sf_tab[428];
extern float ff_aac_pow34sf_tab[428];
#endif /* CONFIG_HARDCODED_TABLES */
#endif /* AVCODEC_AAC_TABLEGEN_DECL_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,192 @@
/*
* AAC encoder trellis codebook selector
* Copyright (C) 2008-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
* AAC encoder trellis codebook selector
* @author Konstantin Shishkov
*/
/**
* This file contains a template for the codebook_trellis_rate selector function.
* It needs to be provided, externally, as an already included declaration,
* the following functions from aacenc_quantization/util.h. They're not included
* explicitly here to make it possible to provide alternative implementations:
* - quantize_band_cost_bits
* - abs_pow34_v
*/
#ifndef AVCODEC_AACCODER_TRELLIS_H
#define AVCODEC_AACCODER_TRELLIS_H
#include <float.h>
#include "libavutil/mathematics.h"
#include "avcodec.h"
#include "put_bits.h"
#include "aac.h"
#include "aacenc.h"
#include "aactab.h"
#include "aacenctab.h"
/**
* structure used in optimal codebook search
*/
typedef struct TrellisBandCodingPath {
int prev_idx; ///< pointer to the previous path point
float cost; ///< path cost
int run;
} TrellisBandCodingPath;
static void codebook_trellis_rate(AACEncContext *s, SingleChannelElement *sce,
int win, int group_len, const float lambda)
{
TrellisBandCodingPath path[120][CB_TOT_ALL];
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 < CB_TOT_ALL; 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 < CB_TOT_ALL; 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];
startcb = aac_cb_in_map[startcb];
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 < CB_TOT_ALL; cb++) {
float cost_stay_here, cost_get_here;
float bits = 0.0f;
if (cb >= 12 && sce->band_type[win*16+swb] != aac_cb_out_map[cb]) {
path[swb+1][cb].cost = 61450;
path[swb+1][cb].prev_idx = -1;
path[swb+1][cb].run = 0;
continue;
}
for (w = 0; w < group_len; w++) {
bits += quantize_band_cost_bits(s, &sce->coeffs[start + w*128],
&s->scoefs[start + w*128], size,
sce->sf_idx[win*16+swb],
aac_cb_out_map[cb],
0, INFINITY, NULL, NULL, 0);
}
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];
}
//convert resulting path from backward-linked list
stack_len = 0;
idx = 0;
for (cb = 1; cb < CB_TOT_ALL; 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++;
}
//perform actual band info encoding
start = 0;
for (i = stack_len - 1; i >= 0; i--) {
cb = aac_cb_out_map[stackcb[i]];
put_bits(&s->pb, 4, cb);
count = stackrun[i];
memset(sce->zeroes + win*16 + start, !cb, count);
//XXX: memset when band_type is also uint8_t
for (j = 0; j < count; j++) {
sce->band_type[win*16 + start] = cb;
start++;
}
while (count >= run_esc) {
put_bits(&s->pb, run_bits, run_esc);
count -= run_esc;
}
put_bits(&s->pb, run_bits, count);
}
}
#endif /* AVCODEC_AACCODER_TRELLIS_H */

View File

@ -0,0 +1,755 @@
/*
* AAC encoder twoloop coder
* Copyright (C) 2008-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
* AAC encoder twoloop coder
* @author Konstantin Shishkov, Claudio Freire
*/
/**
* This file contains a template for the twoloop coder function.
* It needs to be provided, externally, as an already included declaration,
* the following functions from aacenc_quantization/util.h. They're not included
* explicitly here to make it possible to provide alternative implementations:
* - quantize_band_cost
* - abs_pow34_v
* - find_max_val
* - find_min_book
* - find_form_factor
*/
#ifndef AVCODEC_AACCODER_TWOLOOP_H
#define AVCODEC_AACCODER_TWOLOOP_H
#include <float.h>
#include "libavutil/mathematics.h"
#include "mathops.h"
#include "avcodec.h"
#include "put_bits.h"
#include "aac.h"
#include "aacenc.h"
#include "aactab.h"
#include "aacenctab.h"
/** Frequency in Hz for lower limit of noise substitution **/
#define NOISE_LOW_LIMIT 4000
#define sclip(x) av_clip(x,60,218)
/* Reflects the cost to change codebooks */
static inline int ff_pns_bits(SingleChannelElement *sce, int w, int g)
{
return (!g || !sce->zeroes[w*16+g-1] || !sce->can_pns[w*16+g-1]) ? 9 : 5;
}
/**
* two-loop quantizers search taken from ISO 13818-7 Appendix C
*/
static void search_for_quantizers_twoloop(AVCodecContext *avctx,
AACEncContext *s,
SingleChannelElement *sce,
const float lambda)
{
int start = 0, i, w, w2, g, recomprd;
int destbits = avctx->bit_rate * 1024.0 / avctx->sample_rate
/ ((avctx->flags & CODEC_FLAG_QSCALE) ? 2.0f : avctx->channels)
* (lambda / 120.f);
int refbits = destbits;
int toomanybits, toofewbits;
char nzs[128];
uint8_t nextband[128];
int maxsf[128];
float dists[128] = { 0 }, qenergies[128] = { 0 }, uplims[128], euplims[128], energies[128];
float maxvals[128], spread_thr_r[128];
float min_spread_thr_r, max_spread_thr_r;
/**
* rdlambda controls the maximum tolerated distortion. Twoloop
* will keep iterating until it fails to lower it or it reaches
* ulimit * rdlambda. Keeping it low increases quality on difficult
* signals, but lower it too much, and bits will be taken from weak
* signals, creating "holes". A balance is necesary.
* rdmax and rdmin specify the relative deviation from rdlambda
* allowed for tonality compensation
*/
float rdlambda = av_clipf(2.0f * 120.f / lambda, 0.0625f, 16.0f);
const float nzslope = 1.5f;
float rdmin = 0.03125f;
float rdmax = 1.0f;
/**
* sfoffs controls an offset of optmium allocation that will be
* applied based on lambda. Keep it real and modest, the loop
* will take care of the rest, this just accelerates convergence
*/
float sfoffs = av_clipf(log2f(120.0f / lambda) * 4.0f, -5, 10);
int fflag, minscaler, maxscaler, nminscaler;
int its = 0;
int maxits = 30;
int allz = 0;
int tbits;
int cutoff = 1024;
int pns_start_pos;
int prev;
/**
* zeroscale controls a multiplier of the threshold, if band energy
* is below this, a zero is forced. Keep it lower than 1, unless
* low lambda is used, because energy < threshold doesn't mean there's
* no audible signal outright, it's just energy. Also make it rise
* slower than rdlambda, as rdscale has due compensation with
* noisy band depriorization below, whereas zeroing logic is rather dumb
*/
float zeroscale;
if (lambda > 120.f) {
zeroscale = av_clipf(powf(120.f / lambda, 0.25f), 0.0625f, 1.0f);
} else {
zeroscale = 1.f;
}
if (s->psy.bitres.alloc >= 0) {
/**
* Psy granted us extra bits to use, from the reservoire
* adjust for lambda except what psy already did
*/
destbits = s->psy.bitres.alloc
* (lambda / (avctx->global_quality ? avctx->global_quality : 120));
}
if (avctx->flags & CODEC_FLAG_QSCALE) {
/**
* Constant Q-scale doesn't compensate MS coding on its own
* No need to be overly precise, this only controls RD
* adjustment CB limits when going overboard
*/
if (s->options.mid_side && s->cur_type == TYPE_CPE)
destbits *= 2;
/**
* When using a constant Q-scale, don't adjust bits, just use RD
* Don't let it go overboard, though... 8x psy target is enough
*/
toomanybits = 5800;
toofewbits = destbits / 16;
/** Don't offset scalers, just RD */
sfoffs = sce->ics.num_windows - 1;
rdlambda = sqrtf(rdlambda);
/** search further */
maxits *= 2;
} else {
/* When using ABR, be strict, but a reasonable leeway is
* critical to allow RC to smoothly track desired bitrate
* without sudden quality drops that cause audible artifacts.
* Symmetry is also desirable, to avoid systematic bias.
*/
toomanybits = destbits + destbits/8;
toofewbits = destbits - destbits/8;
sfoffs = 0;
rdlambda = sqrtf(rdlambda);
}
/** and zero out above cutoff frequency */
{
int wlen = 1024 / sce->ics.num_windows;
int bandwidth;
/**
* Scale, psy gives us constant quality, this LP only scales
* bitrate by lambda, so we save bits on subjectively unimportant HF
* rather than increase quantization noise. Adjust nominal bitrate
* to effective bitrate according to encoding parameters,
* AAC_CUTOFF_FROM_BITRATE is calibrated for effective bitrate.
*/
float rate_bandwidth_multiplier = 1.5f;
int frame_bit_rate = (avctx->flags & CODEC_FLAG_QSCALE)
? (refbits * rate_bandwidth_multiplier * avctx->sample_rate / 1024)
: (avctx->bit_rate / avctx->channels);
/** Compensate for extensions that increase efficiency */
if (s->options.pns || s->options.intensity_stereo)
frame_bit_rate *= 1.15f;
if (avctx->cutoff > 0) {
bandwidth = avctx->cutoff;
} else {
bandwidth = FFMAX(3000, AAC_CUTOFF_FROM_BITRATE(frame_bit_rate, 1, avctx->sample_rate));
s->psy.cutoff = bandwidth;
}
cutoff = bandwidth * 2 * wlen / avctx->sample_rate;
pns_start_pos = NOISE_LOW_LIMIT * 2 * wlen / avctx->sample_rate;
}
/**
* for values above this the decoder might end up in an endless loop
* due to always having more bits than what can be encoded.
*/
destbits = FFMIN(destbits, 5800);
toomanybits = FFMIN(toomanybits, 5800);
toofewbits = FFMIN(toofewbits, 5800);
/**
* XXX: some heuristic to determine initial quantizers will reduce search time
* determine zero bands and upper distortion limits
*/
min_spread_thr_r = -1;
max_spread_thr_r = -1;
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
for (g = start = 0; g < sce->ics.num_swb; start += sce->ics.swb_sizes[g++]) {
int nz = 0;
float uplim = 0.0f, energy = 0.0f, spread = 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];
if (start >= cutoff || band->energy <= (band->threshold * zeroscale) || band->threshold == 0.0f) {
sce->zeroes[(w+w2)*16+g] = 1;
continue;
}
nz = 1;
}
if (!nz) {
uplim = 0.0f;
} else {
nz = 0;
for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g];
if (band->energy <= (band->threshold * zeroscale) || band->threshold == 0.0f)
continue;
uplim += band->threshold;
energy += band->energy;
spread += band->spread;
nz++;
}
}
uplims[w*16+g] = uplim;
energies[w*16+g] = energy;
nzs[w*16+g] = nz;
sce->zeroes[w*16+g] = !nz;
allz |= nz;
if (nz && sce->can_pns[w*16+g]) {
spread_thr_r[w*16+g] = energy * nz / (uplim * spread);
if (min_spread_thr_r < 0) {
min_spread_thr_r = max_spread_thr_r = spread_thr_r[w*16+g];
} else {
min_spread_thr_r = FFMIN(min_spread_thr_r, spread_thr_r[w*16+g]);
max_spread_thr_r = FFMAX(max_spread_thr_r, spread_thr_r[w*16+g]);
}
}
}
}
/** Compute initial scalers */
minscaler = 65535;
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;
}
/**
* log2f-to-distortion ratio is, technically, 2 (1.5db = 4, but it's power vs level so it's 2).
* But, as offsets are applied, low-frequency signals are too sensitive to the induced distortion,
* so we make scaling more conservative by choosing a lower log2f-to-distortion ratio, and thus
* more robust.
*/
sce->sf_idx[w*16+g] = av_clip(
SCALE_ONE_POS
+ 1.75*log2f(FFMAX(0.00125f,uplims[w*16+g]) / sce->ics.swb_sizes[g])
+ sfoffs,
60, SCALE_MAX_POS);
minscaler = FFMIN(minscaler, sce->sf_idx[w*16+g]);
}
}
/** Clip */
minscaler = av_clip(minscaler, SCALE_ONE_POS - SCALE_DIV_512, SCALE_MAX_POS - SCALE_DIV_512);
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] = av_clip(sce->sf_idx[w*16+g], minscaler, minscaler + SCALE_MAX_DIFF - 1);
if (!allz)
return;
abs_pow34_v(s->scoefs, sce->coeffs, 1024);
ff_quantize_band_cost_cache_init(s);
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];
}
}
/**
* Scale uplims to match rate distortion to quality
* bu applying noisy band depriorization and tonal band priorization.
* Maxval-energy ratio gives us an idea of how noisy/tonal the band is.
* If maxval^2 ~ energy, then that band is mostly noise, and we can relax
* rate distortion requirements.
*/
memcpy(euplims, uplims, sizeof(euplims));
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
/** psy already priorizes transients to some extent */
float de_psy_factor = (sce->ics.num_windows > 1) ? 8.0f / sce->ics.group_len[w] : 1.0f;
start = w*128;
for (g = 0; g < sce->ics.num_swb; g++) {
if (nzs[g] > 0) {
float cleanup_factor = ff_sqrf(av_clipf(start / (cutoff * 0.75f), 1.0f, 2.0f));
float energy2uplim = find_form_factor(
sce->ics.group_len[w], sce->ics.swb_sizes[g],
uplims[w*16+g] / (nzs[g] * sce->ics.swb_sizes[w]),
sce->coeffs + start,
nzslope * cleanup_factor);
energy2uplim *= de_psy_factor;
if (!(avctx->flags & CODEC_FLAG_QSCALE)) {
/** In ABR, we need to priorize less and let rate control do its thing */
energy2uplim = sqrtf(energy2uplim);
}
energy2uplim = FFMAX(0.015625f, FFMIN(1.0f, energy2uplim));
uplims[w*16+g] *= av_clipf(rdlambda * energy2uplim, rdmin, rdmax)
* sce->ics.group_len[w];
energy2uplim = find_form_factor(
sce->ics.group_len[w], sce->ics.swb_sizes[g],
uplims[w*16+g] / (nzs[g] * sce->ics.swb_sizes[w]),
sce->coeffs + start,
2.0f);
energy2uplim *= de_psy_factor;
if (!(avctx->flags & CODEC_FLAG_QSCALE)) {
/** In ABR, we need to priorize less and let rate control do its thing */
energy2uplim = sqrtf(energy2uplim);
}
energy2uplim = FFMAX(0.015625f, FFMIN(1.0f, energy2uplim));
euplims[w*16+g] *= av_clipf(rdlambda * energy2uplim * sce->ics.group_len[w],
0.5f, 1.0f);
}
start += sce->ics.swb_sizes[g];
}
}
for (i = 0; i < sizeof(maxsf) / sizeof(maxsf[0]); ++i)
maxsf[i] = SCALE_MAX_POS;
//perform two-loop search
//outer loop - improve quality
do {
//inner loop - quantize spectrum to fit into given number of bits
int overdist;
int qstep = its ? 1 : 32;
do {
int changed = 0;
prev = -1;
recomprd = 0;
tbits = 0;
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
start = w*128;
for (g = 0; g < sce->ics.num_swb; g++) {
const float *coefs = &sce->coeffs[start];
const float *scaled = &s->scoefs[start];
int bits = 0;
int cb;
float dist = 0.0f;
float qenergy = 0.0f;
if (sce->zeroes[w*16+g] || sce->sf_idx[w*16+g] >= 218) {
start += sce->ics.swb_sizes[g];
if (sce->can_pns[w*16+g]) {
/** PNS isn't free */
tbits += ff_pns_bits(sce, w, g);
}
continue;
}
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;
float sqenergy;
dist += quantize_band_cost_cached(s, w + w2, g, coefs + w2*128,
scaled + w2*128,
sce->ics.swb_sizes[g],
sce->sf_idx[w*16+g],
cb,
1.0f,
INFINITY,
&b, &sqenergy,
0);
bits += b;
qenergy += sqenergy;
}
dists[w*16+g] = dist - bits;
qenergies[w*16+g] = qenergy;
if (prev != -1) {
int sfdiff = av_clip(sce->sf_idx[w*16+g] - prev + SCALE_DIFF_ZERO, 0, 2*SCALE_MAX_DIFF);
bits += ff_aac_scalefactor_bits[sfdiff];
}
tbits += bits;
start += sce->ics.swb_sizes[g];
prev = sce->sf_idx[w*16+g];
}
}
if (tbits > toomanybits) {
recomprd = 1;
for (i = 0; i < 128; i++) {
if (sce->sf_idx[i] < (SCALE_MAX_POS - SCALE_DIV_512)) {
int maxsf_i = (tbits > 5800) ? SCALE_MAX_POS : maxsf[i];
int new_sf = FFMIN(maxsf_i, sce->sf_idx[i] + qstep);
if (new_sf != sce->sf_idx[i]) {
sce->sf_idx[i] = new_sf;
changed = 1;
}
}
}
} else if (tbits < toofewbits) {
recomprd = 1;
for (i = 0; i < 128; i++) {
if (sce->sf_idx[i] > SCALE_ONE_POS) {
int new_sf = FFMAX(SCALE_ONE_POS, sce->sf_idx[i] - qstep);
if (new_sf != sce->sf_idx[i]) {
sce->sf_idx[i] = new_sf;
changed = 1;
}
}
}
}
qstep >>= 1;
if (!qstep && tbits > toomanybits && sce->sf_idx[0] < 217 && changed)
qstep = 1;
} while (qstep);
overdist = 1;
fflag = tbits < toofewbits;
for (i = 0; i < 2 && (overdist || recomprd); ++i) {
if (recomprd) {
/** Must recompute distortion */
prev = -1;
tbits = 0;
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
start = w*128;
for (g = 0; g < sce->ics.num_swb; g++) {
const float *coefs = sce->coeffs + start;
const float *scaled = s->scoefs + start;
int bits = 0;
int cb;
float dist = 0.0f;
float qenergy = 0.0f;
if (sce->zeroes[w*16+g] || sce->sf_idx[w*16+g] >= 218) {
start += sce->ics.swb_sizes[g];
if (sce->can_pns[w*16+g]) {
/** PNS isn't free */
tbits += ff_pns_bits(sce, w, g);
}
continue;
}
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;
float sqenergy;
dist += quantize_band_cost_cached(s, w + w2, g, coefs + w2*128,
scaled + w2*128,
sce->ics.swb_sizes[g],
sce->sf_idx[w*16+g],
cb,
1.0f,
INFINITY,
&b, &sqenergy,
0);
bits += b;
qenergy += sqenergy;
}
dists[w*16+g] = dist - bits;
qenergies[w*16+g] = qenergy;
if (prev != -1) {
int sfdiff = av_clip(sce->sf_idx[w*16+g] - prev + SCALE_DIFF_ZERO, 0, 2*SCALE_MAX_DIFF);
bits += ff_aac_scalefactor_bits[sfdiff];
}
tbits += bits;
start += sce->ics.swb_sizes[g];
prev = sce->sf_idx[w*16+g];
}
}
}
if (!i && s->options.pns && its > maxits/2 && tbits > toofewbits) {
float maxoverdist = 0.0f;
float ovrfactor = 1.f+(maxits-its)*16.f/maxits;
overdist = recomprd = 0;
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
for (g = start = 0; g < sce->ics.num_swb; start += sce->ics.swb_sizes[g++]) {
if (!sce->zeroes[w*16+g] && sce->sf_idx[w*16+g] > SCALE_ONE_POS && dists[w*16+g] > uplims[w*16+g]*ovrfactor) {
float ovrdist = dists[w*16+g] / FFMAX(uplims[w*16+g],euplims[w*16+g]);
maxoverdist = FFMAX(maxoverdist, ovrdist);
overdist++;
}
}
}
if (overdist) {
/* We have overdistorted bands, trade for zeroes (that can be noise)
* Zero the bands in the lowest 1.25% spread-energy-threshold ranking
*/
float minspread = max_spread_thr_r;
float maxspread = min_spread_thr_r;
float zspread;
int zeroable = 0;
int zeroed = 0;
int maxzeroed, zloop;
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
for (g = start = 0; g < sce->ics.num_swb; start += sce->ics.swb_sizes[g++]) {
if (start >= pns_start_pos && !sce->zeroes[w*16+g] && sce->can_pns[w*16+g]) {
minspread = FFMIN(minspread, spread_thr_r[w*16+g]);
maxspread = FFMAX(maxspread, spread_thr_r[w*16+g]);
zeroable++;
}
}
}
zspread = (maxspread-minspread) * 0.0125f + minspread;
/* Don't PNS everything even if allowed. It suppresses bit starvation signals from RC,
* and forced the hand of the later search_for_pns step.
* Instead, PNS a fraction of the spread_thr_r range depending on how starved for bits we are,
* and leave further PNSing to search_for_pns if worthwhile.
*/
zspread = FFMIN3(min_spread_thr_r * 8.f, zspread,
((toomanybits - tbits) * min_spread_thr_r + (tbits - toofewbits) * max_spread_thr_r) / (toomanybits - toofewbits + 1));
maxzeroed = FFMIN(zeroable, FFMAX(1, (zeroable * its + maxits - 1) / (2 * maxits)));
for (zloop = 0; zloop < 2; zloop++) {
/* Two passes: first distorted stuff - two birds in one shot and all that,
* then anything viable. Viable means not zero, but either CB=zero-able
* (too high SF), not SF <= 1 (that means we'd be operating at very high
* quality, we don't want PNS when doing VHQ), PNS allowed, and within
* the lowest ranking percentile.
*/
float loopovrfactor = (zloop) ? 1.0f : ovrfactor;
int loopminsf = (zloop) ? (SCALE_ONE_POS - SCALE_DIV_512) : SCALE_ONE_POS;
int mcb;
for (g = sce->ics.num_swb-1; g > 0 && zeroed < maxzeroed; g--) {
if (sce->ics.swb_offset[g] < pns_start_pos)
continue;
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
if (!sce->zeroes[w*16+g] && sce->can_pns[w*16+g] && spread_thr_r[w*16+g] <= zspread
&& sce->sf_idx[w*16+g] > loopminsf
&& (dists[w*16+g] > loopovrfactor*uplims[w*16+g] || !(mcb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]))
|| (mcb <= 1 && dists[w*16+g] > FFMIN(uplims[w*16+g], euplims[w*16+g]))) ) {
sce->zeroes[w*16+g] = 1;
sce->band_type[w*16+g] = 0;
zeroed++;
}
}
}
}
if (zeroed)
recomprd = fflag = 1;
} else {
overdist = 0;
}
}
}
minscaler = SCALE_MAX_POS;
maxscaler = 0;
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
for (g = 0; g < sce->ics.num_swb; g++) {
if (!sce->zeroes[w*16+g]) {
minscaler = FFMIN(minscaler, sce->sf_idx[w*16+g]);
maxscaler = FFMAX(maxscaler, sce->sf_idx[w*16+g]);
}
}
}
minscaler = nminscaler = av_clip(minscaler, SCALE_ONE_POS - SCALE_DIV_512, SCALE_MAX_POS - SCALE_DIV_512);
prev = -1;
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
/** Start with big steps, end up fine-tunning */
int depth = (its > maxits/2) ? ((its > maxits*2/3) ? 1 : 3) : 10;
int edepth = depth+2;
float uplmax = its / (maxits*0.25f) + 1.0f;
uplmax *= (tbits > destbits) ? FFMIN(2.0f, tbits / (float)FFMAX(1,destbits)) : 1.0f;
start = w * 128;
for (g = 0; g < sce->ics.num_swb; g++) {
int prevsc = sce->sf_idx[w*16+g];
if (prev < 0 && !sce->zeroes[w*16+g])
prev = sce->sf_idx[0];
if (!sce->zeroes[w*16+g]) {
const float *coefs = sce->coeffs + start;
const float *scaled = s->scoefs + start;
int cmb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]);
int mindeltasf = FFMAX(0, prev - SCALE_MAX_DIFF);
int maxdeltasf = FFMIN(SCALE_MAX_POS - SCALE_DIV_512, prev + SCALE_MAX_DIFF);
if ((!cmb || dists[w*16+g] > uplims[w*16+g]) && sce->sf_idx[w*16+g] > mindeltasf) {
/* Try to make sure there is some energy in every nonzero band
* NOTE: This algorithm must be forcibly imbalanced, pushing harder
* on holes or more distorted bands at first, otherwise there's
* no net gain (since the next iteration will offset all bands
* on the opposite direction to compensate for extra bits)
*/
for (i = 0; i < edepth && sce->sf_idx[w*16+g] > mindeltasf; ++i) {
int cb, bits;
float dist, qenergy;
int mb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]-1);
cb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]);
dist = qenergy = 0.f;
bits = 0;
if (!cb) {
maxsf[w*16+g] = FFMIN(sce->sf_idx[w*16+g]-1, maxsf[w*16+g]);
} else if (i >= depth && dists[w*16+g] < euplims[w*16+g]) {
break;
}
/* !g is the DC band, it's important, since quantization error here
* applies to less than a cycle, it creates horrible intermodulation
* distortion if it doesn't stick to what psy requests
*/
if (!g && sce->ics.num_windows > 1 && dists[w*16+g] >= euplims[w*16+g])
maxsf[w*16+g] = FFMIN(sce->sf_idx[w*16+g], maxsf[w*16+g]);
for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
int b;
float sqenergy;
dist += quantize_band_cost_cached(s, w + w2, g, coefs + w2*128,
scaled + w2*128,
sce->ics.swb_sizes[g],
sce->sf_idx[w*16+g]-1,
cb,
1.0f,
INFINITY,
&b, &sqenergy,
0);
bits += b;
qenergy += sqenergy;
}
sce->sf_idx[w*16+g]--;
dists[w*16+g] = dist - bits;
qenergies[w*16+g] = qenergy;
if (mb && (sce->sf_idx[w*16+g] < mindeltasf || (
(dists[w*16+g] < FFMIN(uplmax*uplims[w*16+g], euplims[w*16+g]))
&& (fabsf(qenergies[w*16+g]-energies[w*16+g]) < euplims[w*16+g])
) )) {
break;
}
}
} else if (tbits > toofewbits && sce->sf_idx[w*16+g] < FFMIN(maxdeltasf, maxsf[w*16+g])
&& (dists[w*16+g] < FFMIN(euplims[w*16+g], uplims[w*16+g]))
&& (fabsf(qenergies[w*16+g]-energies[w*16+g]) < euplims[w*16+g])
) {
/** Um... over target. Save bits for more important stuff. */
for (i = 0; i < depth && sce->sf_idx[w*16+g] < maxdeltasf; ++i) {
int cb, bits;
float dist, qenergy;
cb = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]+1);
if (cb > 0) {
dist = qenergy = 0.f;
bits = 0;
for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
int b;
float sqenergy;
dist += quantize_band_cost_cached(s, w + w2, g, coefs + w2*128,
scaled + w2*128,
sce->ics.swb_sizes[g],
sce->sf_idx[w*16+g]+1,
cb,
1.0f,
INFINITY,
&b, &sqenergy,
0);
bits += b;
qenergy += sqenergy;
}
dist -= bits;
if (dist < FFMIN(euplims[w*16+g], uplims[w*16+g])) {
sce->sf_idx[w*16+g]++;
dists[w*16+g] = dist;
qenergies[w*16+g] = qenergy;
} else {
break;
}
} else {
maxsf[w*16+g] = FFMIN(sce->sf_idx[w*16+g], maxsf[w*16+g]);
break;
}
}
}
prev = sce->sf_idx[w*16+g] = av_clip(sce->sf_idx[w*16+g], mindeltasf, maxdeltasf);
if (sce->sf_idx[w*16+g] != prevsc)
fflag = 1;
nminscaler = FFMIN(nminscaler, sce->sf_idx[w*16+g]);
sce->band_type[w*16+g] = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]);
}
start += sce->ics.swb_sizes[g];
}
}
/** SF difference limit violation risk. Must re-clamp. */
prev = -1;
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]) {
int prevsf = sce->sf_idx[w*16+g];
if (prev < 0)
prev = prevsf;
sce->sf_idx[w*16+g] = av_clip(sce->sf_idx[w*16+g], prev - SCALE_MAX_DIFF, prev + SCALE_MAX_DIFF);
sce->band_type[w*16+g] = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]);
prev = sce->sf_idx[w*16+g];
if (!fflag && prevsf != sce->sf_idx[w*16+g])
fflag = 1;
}
}
}
its++;
} while (fflag && its < maxits);
/** Scout out next nonzero bands */
ff_init_nextband_map(sce, nextband);
prev = -1;
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
/** Make sure proper codebooks are set */
for (g = 0; g < sce->ics.num_swb; g++) {
if (!sce->zeroes[w*16+g]) {
sce->band_type[w*16+g] = find_min_book(maxvals[w*16+g], sce->sf_idx[w*16+g]);
if (sce->band_type[w*16+g] <= 0) {
if (!ff_sfdelta_can_remove_band(sce, nextband, prev, w*16+g)) {
/** Cannot zero out, make sure it's not attempted */
sce->band_type[w*16+g] = 1;
} else {
sce->zeroes[w*16+g] = 1;
sce->band_type[w*16+g] = 0;
}
}
} else {
sce->band_type[w*16+g] = 0;
}
/** Check that there's no SF delta range violations */
if (!sce->zeroes[w*16+g]) {
if (prev != -1) {
av_unused int sfdiff = sce->sf_idx[w*16+g] - prev + SCALE_DIFF_ZERO;
av_assert1(sfdiff >= 0 && sfdiff <= 2*SCALE_MAX_DIFF);
} else if (sce->zeroes[0]) {
/** Set global gain to something useful */
sce->sf_idx[0] = sce->sf_idx[w*16+g];
}
prev = sce->sf_idx[w*16+g];
}
}
}
}
#endif /* AVCODEC_AACCODER_TWOLOOP_H */

View File

@ -55,6 +55,7 @@
#include "aacsbr.h"
#include "mpeg4audio.h"
#include "aacadtsdec.h"
#include "profiles.h"
#include "libavutil/intfloat.h"
#include <errno.h>
@ -551,10 +552,11 @@ AVCodec ff_aac_decoder = {
AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE
},
.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
.channel_layouts = aac_channel_layout,
.flush = flush,
.priv_class = &aac_decoder_class,
.profiles = profiles,
.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles),
};
/*
@ -575,7 +577,8 @@ AVCodec ff_aac_latm_decoder = {
AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE
},
.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
.channel_layouts = aac_channel_layout,
.flush = flush,
.profiles = profiles,
.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles),
};

View File

@ -80,6 +80,7 @@
#include "aacsbr.h"
#include "mpeg4audio.h"
#include "aacadtsdec.h"
#include "profiles.h"
#include "libavutil/intfloat.h"
#include <math.h>
@ -438,6 +439,8 @@ AVCodec ff_aac_fixed_decoder = {
AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_NONE
},
.capabilities = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
.channel_layouts = aac_channel_layout,
.profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles),
.flush = flush,
};

View File

@ -89,6 +89,8 @@
Parametric Stereo.
*/
#include "libavutil/thread.h"
static VLC vlc_scalefactors;
static VLC vlc_spectral[11];
@ -1067,11 +1069,55 @@ static void reset_predictor_group(PredictorState *ps, int group_num)
static void aacdec_init(AACContext *ac);
static av_cold void aac_static_table_init(void)
{
AAC_INIT_VLC_STATIC( 0, 304);
AAC_INIT_VLC_STATIC( 1, 270);
AAC_INIT_VLC_STATIC( 2, 550);
AAC_INIT_VLC_STATIC( 3, 300);
AAC_INIT_VLC_STATIC( 4, 328);
AAC_INIT_VLC_STATIC( 5, 294);
AAC_INIT_VLC_STATIC( 6, 306);
AAC_INIT_VLC_STATIC( 7, 268);
AAC_INIT_VLC_STATIC( 8, 510);
AAC_INIT_VLC_STATIC( 9, 366);
AAC_INIT_VLC_STATIC(10, 462);
AAC_RENAME(ff_aac_sbr_init)();
ff_aac_tableinit();
INIT_VLC_STATIC(&vlc_scalefactors, 7,
FF_ARRAY_ELEMS(ff_aac_scalefactor_code),
ff_aac_scalefactor_bits,
sizeof(ff_aac_scalefactor_bits[0]),
sizeof(ff_aac_scalefactor_bits[0]),
ff_aac_scalefactor_code,
sizeof(ff_aac_scalefactor_code[0]),
sizeof(ff_aac_scalefactor_code[0]),
352);
// window initialization
AAC_RENAME(ff_kbd_window_init)(AAC_RENAME(ff_aac_kbd_long_1024), 4.0, 1024);
AAC_RENAME(ff_kbd_window_init)(AAC_RENAME(ff_aac_kbd_short_128), 6.0, 128);
AAC_RENAME(ff_init_ff_sine_windows)(10);
AAC_RENAME(ff_init_ff_sine_windows)( 9);
AAC_RENAME(ff_init_ff_sine_windows)( 7);
AAC_RENAME(cbrt_tableinit)();
}
static AVOnce aac_table_init = AV_ONCE_INIT;
static av_cold int aac_decode_init(AVCodecContext *avctx)
{
AACContext *ac = avctx->priv_data;
int ret;
ret = ff_thread_once(&aac_table_init, &aac_static_table_init);
if (ret != 0)
return AVERROR_UNKNOWN;
ac->avctx = avctx;
ac->oc[1].m4ac.sample_rate = avctx->sample_rate;
@ -1123,20 +1169,6 @@ static av_cold int aac_decode_init(AVCodecContext *avctx)
return AVERROR_INVALIDDATA;
}
AAC_INIT_VLC_STATIC( 0, 304);
AAC_INIT_VLC_STATIC( 1, 270);
AAC_INIT_VLC_STATIC( 2, 550);
AAC_INIT_VLC_STATIC( 3, 300);
AAC_INIT_VLC_STATIC( 4, 328);
AAC_INIT_VLC_STATIC( 5, 294);
AAC_INIT_VLC_STATIC( 6, 306);
AAC_INIT_VLC_STATIC( 7, 268);
AAC_INIT_VLC_STATIC( 8, 510);
AAC_INIT_VLC_STATIC( 9, 366);
AAC_INIT_VLC_STATIC(10, 462);
AAC_RENAME(ff_aac_sbr_init)();
#if USE_FIXED
ac->fdsp = avpriv_alloc_fixed_dsp(avctx->flags & AV_CODEC_FLAG_BITEXACT);
#else
@ -1148,18 +1180,6 @@ static av_cold int aac_decode_init(AVCodecContext *avctx)
ac->random_state = 0x1f2e3d4c;
ff_aac_tableinit();
INIT_VLC_STATIC(&vlc_scalefactors, 7,
FF_ARRAY_ELEMS(ff_aac_scalefactor_code),
ff_aac_scalefactor_bits,
sizeof(ff_aac_scalefactor_bits[0]),
sizeof(ff_aac_scalefactor_bits[0]),
ff_aac_scalefactor_code,
sizeof(ff_aac_scalefactor_code[0]),
sizeof(ff_aac_scalefactor_code[0]),
352);
AAC_RENAME_32(ff_mdct_init)(&ac->mdct, 11, 1, 1.0 / RANGE15(1024.0));
AAC_RENAME_32(ff_mdct_init)(&ac->mdct_ld, 10, 1, 1.0 / RANGE15(512.0));
AAC_RENAME_32(ff_mdct_init)(&ac->mdct_small, 8, 1, 1.0 / RANGE15(128.0));
@ -1169,14 +1189,6 @@ static av_cold int aac_decode_init(AVCodecContext *avctx)
if (ret < 0)
return ret;
#endif
// window initialization
AAC_RENAME(ff_kbd_window_init)(AAC_RENAME(ff_aac_kbd_long_1024), 4.0, 1024);
AAC_RENAME(ff_kbd_window_init)(AAC_RENAME(ff_aac_kbd_short_128), 6.0, 128);
AAC_RENAME(ff_init_ff_sine_windows)(10);
AAC_RENAME(ff_init_ff_sine_windows)( 9);
AAC_RENAME(ff_init_ff_sine_windows)( 7);
AAC_RENAME(cbrt_tableinit)();
return 0;
}
@ -3224,15 +3236,3 @@ static const AVClass aac_decoder_class = {
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
static const AVProfile profiles[] = {
{ FF_PROFILE_AAC_MAIN, "Main" },
{ FF_PROFILE_AAC_LOW, "LC" },
{ FF_PROFILE_AAC_SSR, "SSR" },
{ FF_PROFILE_AAC_LTP, "LTP" },
{ FF_PROFILE_AAC_HE, "HE-AAC" },
{ FF_PROFILE_AAC_HE_V2, "HE-AACv2" },
{ FF_PROFILE_AAC_LD, "LD" },
{ FF_PROFILE_AAC_ELD, "ELD" },
{ FF_PROFILE_UNKNOWN },
};

View File

@ -35,14 +35,6 @@
#include <stdint.h>
/* @name ltp_coef
* Table of the LTP coefficients
*/
static const INTFLOAT ltp_coef[8] = {
Q30(0.570829f), Q30(0.696616f), Q30(0.813004f), Q30(0.911304f),
Q30(0.984900f), Q30(1.067894f), Q30(1.194601f), Q30(1.369533f),
};
static const int8_t tags_per_config[16] = { 0, 1, 1, 2, 3, 3, 4, 5, 0, 0, 0, 4, 5, 0, 5, 0 };
static const uint8_t aac_channel_layout_map[16][5][3] = {

View File

@ -29,6 +29,8 @@
* add sane pulse detection
***********************************/
#include "libavutil/libm.h"
#include "libavutil/thread.h"
#include "libavutil/float_dsp.h"
#include "libavutil/opt.h"
#include "avcodec.h"
@ -46,6 +48,8 @@
#include "psymodel.h"
static AVOnce aac_table_init = AV_ONCE_INIT;
/**
* Make AAC audio config object.
* @see 1.6.2.1 "Syntax - AudioSpecificConfig"
@ -54,11 +58,12 @@ static void put_audio_specific_config(AVCodecContext *avctx)
{
PutBitContext pb;
AACEncContext *s = avctx->priv_data;
int channels = s->channels - (s->channels == 8 ? 1 : 0);
init_put_bits(&pb, avctx->extradata, avctx->extradata_size);
put_bits(&pb, 5, s->profile+1); //profile
put_bits(&pb, 4, s->samplerate_index); //sample rate index
put_bits(&pb, 4, s->channels);
put_bits(&pb, 4, channels);
//GASpecificConfig
put_bits(&pb, 1, 0); //frame length - 1024 samples
put_bits(&pb, 1, 0); //does not depend on core coder
@ -71,6 +76,16 @@ static void put_audio_specific_config(AVCodecContext *avctx)
flush_put_bits(&pb);
}
void ff_quantize_band_cost_cache_init(struct AACEncContext *s)
{
int sf, g;
for (sf = 0; sf < 256; sf++) {
for (g = 0; g < 128; g++) {
s->quantize_band_cost_cache[sf][g].bits = -1;
}
}
}
#define WINDOW_FUNC(type) \
static void apply_ ##type ##_window(AVFloatDSPContext *fdsp, \
SingleChannelElement *sce, \
@ -140,7 +155,7 @@ static void apply_window_and_mdct(AACEncContext *s, SingleChannelElement *sce,
float *audio)
{
int i;
float *output = sce->ret_buf;
const float *output = sce->ret_buf;
apply_window[sce->ics.window_sequence[0]](s->fdsp, sce, audio);
@ -258,6 +273,8 @@ static void apply_intensity_stereo(ChannelElement *cpe)
start += ics->swb_sizes[g];
continue;
}
if (cpe->ms_mask[w*16 + g])
p *= -1;
for (i = 0; i < ics->swb_sizes[g]; i++) {
float sum = (cpe->ch[0].coeffs[start+i] + p*cpe->ch[1].coeffs[start+i])*scale;
cpe->ch[0].coeffs[start+i] = sum;
@ -279,7 +296,13 @@ static void apply_mid_side_stereo(ChannelElement *cpe)
for (w2 = 0; w2 < ics->group_len[w]; w2++) {
int start = (w+w2) * 128;
for (g = 0; g < ics->num_swb; g++) {
if (!cpe->ms_mask[w*16 + g]) {
/* ms_mask can be used for other purposes in PNS and I/S,
* so must not apply M/S if any band uses either, even if
* ms_mask is set.
*/
if (!cpe->ms_mask[w*16 + g] || cpe->is_mask[w*16 + g]
|| cpe->ch[0].band_type[w*16 + g] >= NOISE_BT
|| cpe->ch[1].band_type[w*16 + g] >= NOISE_BT) {
start += ics->swb_sizes[g];
continue;
}
@ -424,6 +447,8 @@ static int encode_individual_channel(AVCodecContext *avctx, AACEncContext *s,
put_ics_info(s, &sce->ics);
if (s->coder->encode_main_pred)
s->coder->encode_main_pred(s, sce);
if (s->coder->encode_ltp_info)
s->coder->encode_ltp_info(s, sce, 0);
}
encode_band_info(s, sce);
encode_scale_factors(avctx, s, sce);
@ -489,7 +514,9 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
float **samples = s->planar_samples, *samples2, *la, *overlap;
ChannelElement *cpe;
SingleChannelElement *sce;
int i, ch, w, chans, tag, start_ch, ret;
IndividualChannelStream *ics;
int i, its, ch, w, chans, tag, start_ch, ret, frame_bits;
int target_bits, rate_bits, too_many_bits, too_few_bits;
int ms_mode = 0, is_mode = 0, tns_mode = 0, pred_mode = 0;
int chan_el_counter[4];
FFPsyWindowInfo windows[AAC_MAX_CHANNELS];
@ -517,10 +544,12 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
chans = tag == TYPE_CPE ? 2 : 1;
cpe = &s->cpe[i];
for (ch = 0; ch < chans; ch++) {
IndividualChannelStream *ics = &cpe->ch[ch].ics;
int cur_channel = start_ch + ch;
int k;
float clip_avoidance_factor;
overlap = &samples[cur_channel][0];
sce = &cpe->ch[ch];
ics = &sce->ics;
s->cur_channel = start_ch + ch;
overlap = &samples[s->cur_channel][0];
samples2 = overlap + 1024;
la = samples2 + (448+64);
if (!frame)
@ -537,7 +566,7 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
*/
ics->num_swb = s->samplerate_index >= 8 ? 1 : 3;
} else {
wi[ch] = s->psy.model->window(&s->psy, samples2, la, cur_channel,
wi[ch] = s->psy.model->window(&s->psy, samples2, la, s->cur_channel,
ics->window_sequence[0]);
}
ics->window_sequence[1] = ics->window_sequence[0];
@ -571,33 +600,34 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
ics->clip_avoidance_factor = 1.0f;
}
apply_window_and_mdct(s, &cpe->ch[ch], overlap);
apply_window_and_mdct(s, sce, overlap);
if (isnan(cpe->ch[ch].coeffs[ 0]) || isinf(cpe->ch[ch].coeffs[ 0]) ||
isnan(cpe->ch[ch].coeffs[ 128]) || isinf(cpe->ch[ch].coeffs[ 128]) ||
isnan(cpe->ch[ch].coeffs[2*128]) || isinf(cpe->ch[ch].coeffs[2*128]) ||
isnan(cpe->ch[ch].coeffs[3*128]) || isinf(cpe->ch[ch].coeffs[3*128]) ||
isnan(cpe->ch[ch].coeffs[4*128]) || isinf(cpe->ch[ch].coeffs[4*128]) ||
isnan(cpe->ch[ch].coeffs[5*128]) || isinf(cpe->ch[ch].coeffs[5*128]) ||
isnan(cpe->ch[ch].coeffs[6*128]) || isinf(cpe->ch[ch].coeffs[6*128]) ||
isnan(cpe->ch[ch].coeffs[7*128]) || isinf(cpe->ch[ch].coeffs[7*128])) {
av_log(avctx, AV_LOG_ERROR, "Input contains NaN/+-Inf\n");
return AVERROR(EINVAL);
if (s->options.ltp && s->coder->update_ltp) {
s->coder->update_ltp(s, sce);
apply_window[sce->ics.window_sequence[0]](s->fdsp, sce, &sce->ltp_state[0]);
s->mdct1024.mdct_calc(&s->mdct1024, sce->lcoeffs, sce->ret_buf);
}
avoid_clipping(s, &cpe->ch[ch]);
for (k = 0; k < 1024; k++) {
if (!isfinite(cpe->ch[ch].coeffs[k])) {
av_log(avctx, AV_LOG_ERROR, "Input contains NaN/+-Inf\n");
return AVERROR(EINVAL);
}
}
avoid_clipping(s, sce);
}
start_ch += chans;
}
if ((ret = ff_alloc_packet2(avctx, avpkt, 8192 * s->channels, 0)) < 0)
return ret;
frame_bits = its = 0;
do {
int frame_bits;
init_put_bits(&s->pb, avpkt->data, avpkt->size);
if ((avctx->frame_number & 0xFF)==1 && !(avctx->flags & AV_CODEC_FLAG_BITEXACT))
put_bitstream_info(s, LIBAVCODEC_IDENT);
start_ch = 0;
target_bits = 0;
memset(chan_el_counter, 0, sizeof(chan_el_counter));
for (i = 0; i < s->chan_map[0]; i++) {
FFPsyWindowInfo* wi = windows + start_ch;
@ -614,15 +644,28 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
sce = &cpe->ch[ch];
coeffs[ch] = sce->coeffs;
sce->ics.predictor_present = 0;
memset(&sce->ics.prediction_used, 0, sizeof(sce->ics.prediction_used));
sce->ics.ltp.present = 0;
memset(sce->ics.ltp.used, 0, sizeof(sce->ics.ltp.used));
memset(sce->ics.prediction_used, 0, sizeof(sce->ics.prediction_used));
memset(&sce->tns, 0, sizeof(TemporalNoiseShaping));
for (w = 0; w < 128; w++)
if (sce->band_type[w] > RESERVED_BT)
sce->band_type[w] = 0;
}
s->psy.bitres.alloc = -1;
s->psy.bitres.bits = s->last_frame_pb_count / s->channels;
s->psy.model->analyze(&s->psy, start_ch, coeffs, wi);
if (s->psy.bitres.alloc > 0) {
/* Lambda unused here on purpose, we need to take psy's unscaled allocation */
target_bits += s->psy.bitres.alloc
* (s->lambda / (avctx->global_quality ? avctx->global_quality : 120));
s->psy.bitres.alloc /= chans;
}
s->cur_type = tag;
for (ch = 0; ch < chans; ch++) {
s->cur_channel = start_ch + ch;
if (s->options.pns && s->coder->mark_pns)
s->coder->mark_pns(s, avctx, &cpe->ch[ch]);
s->coder->search_for_quantizers(avctx, s, &cpe->ch[ch], s->lambda);
}
if (chans > 1
@ -640,14 +683,14 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
for (ch = 0; ch < chans; ch++) { /* TNS and PNS */
sce = &cpe->ch[ch];
s->cur_channel = start_ch + ch;
if (s->options.pns && s->coder->search_for_pns)
s->coder->search_for_pns(s, avctx, sce);
if (s->options.tns && s->coder->search_for_tns)
s->coder->search_for_tns(s, sce);
if (s->options.tns && s->coder->apply_tns_filt)
s->coder->apply_tns_filt(s, sce);
if (sce->tns.present)
tns_mode = 1;
if (s->options.pns && s->coder->search_for_pns)
s->coder->search_for_pns(s, avctx, sce);
}
s->cur_channel = start_ch;
if (s->options.intensity_stereo) { /* Intensity Stereo */
@ -664,8 +707,8 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
s->coder->search_for_pred(s, sce);
if (cpe->ch[ch].ics.predictor_present) pred_mode = 1;
}
if (s->coder->adjust_common_prediction)
s->coder->adjust_common_prediction(s, cpe);
if (s->coder->adjust_common_pred)
s->coder->adjust_common_pred(s, cpe);
for (ch = 0; ch < chans; ch++) {
sce = &cpe->ch[ch];
s->cur_channel = start_ch + ch;
@ -674,22 +717,34 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
}
s->cur_channel = start_ch;
}
if (s->options.stereo_mode) { /* Mid/Side stereo */
if (s->options.stereo_mode == -1 && s->coder->search_for_ms)
if (s->options.mid_side) { /* Mid/Side stereo */
if (s->options.mid_side == -1 && s->coder->search_for_ms)
s->coder->search_for_ms(s, cpe);
else if (cpe->common_window)
memset(cpe->ms_mask, 1, sizeof(cpe->ms_mask));
for (w = 0; w < 128; w++)
cpe->ms_mask[w] = cpe->is_mask[w] ? 0 : cpe->ms_mask[w];
apply_mid_side_stereo(cpe);
}
adjust_frame_information(cpe, chans);
if (s->options.ltp) { /* LTP */
for (ch = 0; ch < chans; ch++) {
sce = &cpe->ch[ch];
s->cur_channel = start_ch + ch;
if (s->coder->search_for_ltp)
s->coder->search_for_ltp(s, sce, cpe->common_window);
if (sce->ics.ltp.present) pred_mode = 1;
}
s->cur_channel = start_ch;
if (s->coder->adjust_common_ltp)
s->coder->adjust_common_ltp(s, cpe);
}
if (chans == 2) {
put_bits(&s->pb, 1, cpe->common_window);
if (cpe->common_window) {
put_ics_info(s, &cpe->ch[0].ics);
if (s->coder->encode_main_pred)
s->coder->encode_main_pred(s, &cpe->ch[0]);
if (s->coder->encode_ltp_info)
s->coder->encode_ltp_info(s, &cpe->ch[0], 1);
encode_ms_info(&s->pb, cpe);
if (cpe->ms_mode) ms_mode = 1;
}
@ -701,35 +756,77 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
start_ch += chans;
}
frame_bits = put_bits_count(&s->pb);
if (frame_bits <= 6144 * s->channels - 3) {
s->psy.bitres.bits = frame_bits / s->channels;
if (avctx->flags & CODEC_FLAG_QSCALE) {
/* When using a constant Q-scale, don't mess with lambda */
break;
}
if (is_mode || ms_mode || tns_mode || pred_mode) {
for (i = 0; i < s->chan_map[0]; i++) {
// Must restore coeffs
chans = tag == TYPE_CPE ? 2 : 1;
cpe = &s->cpe[i];
for (ch = 0; ch < chans; ch++)
memcpy(cpe->ch[ch].coeffs, cpe->ch[ch].pcoeffs, sizeof(cpe->ch[ch].coeffs));
/* rate control stuff
* allow between the nominal bitrate, and what psy's bit reservoir says to target
* but drift towards the nominal bitrate always
*/
frame_bits = put_bits_count(&s->pb);
rate_bits = avctx->bit_rate * 1024 / avctx->sample_rate;
rate_bits = FFMIN(rate_bits, 6144 * s->channels - 3);
too_many_bits = FFMAX(target_bits, rate_bits);
too_many_bits = FFMIN(too_many_bits, 6144 * s->channels - 3);
too_few_bits = FFMIN(FFMAX(rate_bits - rate_bits/4, target_bits), too_many_bits);
/* When using ABR, be strict (but only for increasing) */
too_few_bits = too_few_bits - too_few_bits/8;
too_many_bits = too_many_bits + too_many_bits/2;
if ( its == 0 /* for steady-state Q-scale tracking */
|| (its < 5 && (frame_bits < too_few_bits || frame_bits > too_many_bits))
|| frame_bits >= 6144 * s->channels - 3 )
{
float ratio = ((float)rate_bits) / frame_bits;
if (frame_bits >= too_few_bits && frame_bits <= too_many_bits) {
/*
* This path is for steady-state Q-scale tracking
* When frame bits fall within the stable range, we still need to adjust
* lambda to maintain it like so in a stable fashion (large jumps in lambda
* create artifacts and should be avoided), but slowly
*/
ratio = sqrtf(sqrtf(ratio));
ratio = av_clipf(ratio, 0.9f, 1.1f);
} else {
/* Not so fast though */
ratio = sqrtf(ratio);
}
s->lambda = FFMIN(s->lambda * ratio, 65536.f);
/* Keep iterating if we must reduce and lambda is in the sky */
if (ratio > 0.9f && ratio < 1.1f) {
break;
} else {
if (is_mode || ms_mode || tns_mode || pred_mode) {
for (i = 0; i < s->chan_map[0]; i++) {
// Must restore coeffs
chans = tag == TYPE_CPE ? 2 : 1;
cpe = &s->cpe[i];
for (ch = 0; ch < chans; ch++)
memcpy(cpe->ch[ch].coeffs, cpe->ch[ch].pcoeffs, sizeof(cpe->ch[ch].coeffs));
}
}
its++;
}
} else {
break;
}
s->lambda *= avctx->bit_rate * 1024.0f / avctx->sample_rate / frame_bits;
} while (1);
if (s->options.ltp && s->coder->ltp_insert_new_frame)
s->coder->ltp_insert_new_frame(s);
put_bits(&s->pb, 3, TYPE_END);
flush_put_bits(&s->pb);
avctx->frame_bits = put_bits_count(&s->pb);
// rate control stuff
if (!(avctx->flags & AV_CODEC_FLAG_QSCALE)) {
float ratio = avctx->bit_rate * 1024.0f / avctx->sample_rate / avctx->frame_bits;
s->lambda *= ratio;
s->lambda = FFMIN(s->lambda, 65536.f);
}
s->last_frame_pb_count = put_bits_count(&s->pb);
s->lambda_sum += s->lambda;
s->lambda_count++;
if (!frame)
s->last_frame++;
@ -746,6 +843,8 @@ static av_cold int aac_encode_end(AVCodecContext *avctx)
{
AACEncContext *s = avctx->priv_data;
av_log(avctx, AV_LOG_INFO, "Qavg: %.3f\n", s->lambda_sum / s->lambda_count);
ff_mdct_end(&s->mdct1024);
ff_mdct_end(&s->mdct128);
ff_psy_end(&s->psy);
@ -796,6 +895,11 @@ alloc_fail:
return AVERROR(ENOMEM);
}
static av_cold void aac_encode_init_tables(void)
{
ff_aac_tableinit();
}
static av_cold int aac_encode_init(AVCodecContext *avctx)
{
AACEncContext *s = avctx->priv_data;
@ -804,45 +908,96 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
uint8_t grouping[AAC_MAX_CHANNELS];
int lengths[2];
/* Constants */
s->last_frame_pb_count = 0;
avctx->extradata_size = 5;
avctx->frame_size = 1024;
avctx->initial_padding = 1024;
s->lambda = avctx->global_quality > 0 ? avctx->global_quality : 120;
/* Channel map and unspecified bitrate guessing */
s->channels = avctx->channels;
ERROR_IF(s->channels > AAC_MAX_CHANNELS || s->channels == 7,
"Unsupported number of channels: %d\n", s->channels);
s->chan_map = aac_chan_configs[s->channels-1];
if (!avctx->bit_rate) {
for (i = 1; i <= s->chan_map[0]; i++) {
avctx->bit_rate += s->chan_map[i] == TYPE_CPE ? 128000 : /* Pair */
s->chan_map[i] == TYPE_LFE ? 16000 : /* LFE */
69000 ; /* SCE */
}
}
/* Samplerate */
for (i = 0; i < 16; i++)
if (avctx->sample_rate == avpriv_mpeg4audio_sample_rates[i])
break;
s->channels = avctx->channels;
ERROR_IF(i == 16 || i >= ff_aac_swb_size_1024_len || i >= ff_aac_swb_size_128_len,
s->samplerate_index = i;
ERROR_IF(s->samplerate_index == 16 ||
s->samplerate_index >= ff_aac_swb_size_1024_len ||
s->samplerate_index >= ff_aac_swb_size_128_len,
"Unsupported sample rate %d\n", avctx->sample_rate);
ERROR_IF(s->channels > AAC_MAX_CHANNELS,
"Unsupported number of channels: %d\n", s->channels);
WARN_IF(1024.0 * avctx->bit_rate / avctx->sample_rate > 6144 * s->channels,
"Too many bits per frame requested, clamping to max\n");
if (avctx->profile == FF_PROFILE_AAC_MAIN) {
s->options.pred = 1;
} else if ((avctx->profile == FF_PROFILE_AAC_LOW ||
avctx->profile == FF_PROFILE_UNKNOWN) && s->options.pred) {
s->profile = 0; /* Main */
WARN_IF(1, "Prediction requested, changing profile to AAC-Main\n");
} else if (avctx->profile == FF_PROFILE_AAC_LOW ||
avctx->profile == FF_PROFILE_UNKNOWN) {
s->profile = 1; /* Low */
} else {
ERROR_IF(1, "Unsupported profile %d\n", avctx->profile);
}
if (s->options.aac_coder != AAC_CODER_TWOLOOP) {
/* Bitrate limiting */
WARN_IF(1024.0 * avctx->bit_rate / avctx->sample_rate > 6144 * s->channels,
"Too many bits %f > %d per frame requested, clamping to max\n",
1024.0 * avctx->bit_rate / avctx->sample_rate,
6144 * s->channels);
avctx->bit_rate = (int64_t)FFMIN(6144 * s->channels / 1024.0 * avctx->sample_rate,
avctx->bit_rate);
/* Profile and option setting */
avctx->profile = avctx->profile == FF_PROFILE_UNKNOWN ? FF_PROFILE_AAC_LOW :
avctx->profile;
for (i = 0; i < FF_ARRAY_ELEMS(aacenc_profiles); i++)
if (avctx->profile == aacenc_profiles[i])
break;
if (avctx->profile == FF_PROFILE_MPEG2_AAC_LOW) {
avctx->profile = FF_PROFILE_AAC_LOW;
ERROR_IF(s->options.pred,
"Main prediction unavailable in the \"mpeg2_aac_low\" profile\n");
ERROR_IF(s->options.ltp,
"LTP prediction unavailable in the \"mpeg2_aac_low\" profile\n");
WARN_IF(s->options.pns,
"PNS unavailable in the \"mpeg2_aac_low\" profile, turning off\n");
s->options.pns = 0;
} else if (avctx->profile == FF_PROFILE_AAC_LTP) {
s->options.ltp = 1;
ERROR_IF(s->options.pred,
"Main prediction unavailable in the \"aac_ltp\" profile\n");
} else if (avctx->profile == FF_PROFILE_AAC_MAIN) {
s->options.pred = 1;
ERROR_IF(s->options.ltp,
"LTP prediction unavailable in the \"aac_main\" profile\n");
} else if (s->options.ltp) {
avctx->profile = FF_PROFILE_AAC_LTP;
WARN_IF(1,
"Chainging profile to \"aac_ltp\"\n");
ERROR_IF(s->options.pred,
"Main prediction unavailable in the \"aac_ltp\" profile\n");
} else if (s->options.pred) {
avctx->profile = FF_PROFILE_AAC_MAIN;
WARN_IF(1,
"Chainging profile to \"aac_main\"\n");
ERROR_IF(s->options.ltp,
"LTP prediction unavailable in the \"aac_main\" profile\n");
}
s->profile = avctx->profile;
/* Coder limitations */
s->coder = &ff_aac_coders[s->options.coder];
if (s->options.coder != AAC_CODER_TWOLOOP) {
ERROR_IF(avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL,
"Coders other than twoloop require -strict -2 and some may be removed in the future\n");
s->options.intensity_stereo = 0;
s->options.pns = 0;
}
ERROR_IF(s->options.ltp && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL,
"The LPT profile requires experimental compliance, add -strict -2 to enable!\n");
avctx->bit_rate = (int)FFMIN(
6144 * s->channels / 1024.0 * avctx->sample_rate,
avctx->bit_rate);
s->samplerate_index = i;
s->chan_map = aac_chan_configs[s->channels-1];
/* M/S introduces horrible artifacts with multichannel files, this is temporary */
if (s->channels > 3)
s->options.mid_side = 0;
if ((ret = dsp_init(avctx, s)) < 0)
goto fail;
@ -850,30 +1005,27 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
if ((ret = alloc_buffers(avctx, s)) < 0)
goto fail;
avctx->extradata_size = 5;
put_audio_specific_config(avctx);
sizes[0] = ff_aac_swb_size_1024[i];
sizes[1] = ff_aac_swb_size_128[i];
lengths[0] = ff_aac_num_swb_1024[i];
lengths[1] = ff_aac_num_swb_128[i];
sizes[0] = ff_aac_swb_size_1024[s->samplerate_index];
sizes[1] = ff_aac_swb_size_128[s->samplerate_index];
lengths[0] = ff_aac_num_swb_1024[s->samplerate_index];
lengths[1] = ff_aac_num_swb_128[s->samplerate_index];
for (i = 0; i < s->chan_map[0]; i++)
grouping[i] = s->chan_map[i + 1] == TYPE_CPE;
if ((ret = ff_psy_init(&s->psy, avctx, 2, sizes, lengths,
s->chan_map[0], grouping)) < 0)
goto fail;
s->psypp = ff_psy_preprocess_init(avctx);
s->coder = &ff_aac_coders[s->options.aac_coder];
ff_lpc_init(&s->lpc, 2*avctx->frame_size, TNS_MAX_ORDER, FF_LPC_TYPE_LEVINSON);
av_lfg_init(&s->lfg, 0x72adca55);
if (HAVE_MIPSDSPR1)
if (HAVE_MIPSDSP)
ff_aac_coder_init_mips(s);
s->lambda = avctx->global_quality > 0 ? avctx->global_quality : 120;
if ((ret = ff_thread_once(&aac_table_init, &aac_encode_init_tables)) != 0)
return AVERROR_UNKNOWN;
ff_aac_tableinit();
avctx->initial_padding = 1024;
ff_af_queue_init(avctx, &s->afq);
return 0;
@ -884,27 +1036,16 @@ fail:
#define AACENC_FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM
static const AVOption aacenc_options[] = {
{"stereo_mode", "Stereo coding method", offsetof(AACEncContext, options.stereo_mode), AV_OPT_TYPE_INT, {.i64 = 0}, -1, 1, AACENC_FLAGS, "stereo_mode"},
{"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", "Coding algorithm", offsetof(AACEncContext, options.aac_coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_TWOLOOP}, 0, AAC_CODER_NB-1, AACENC_FLAGS, "aac_coder"},
{"faac", "FAAC-inspired method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAAC}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"},
{"anmr", "ANMR method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_ANMR}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"},
{"twoloop", "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"},
{"fast", "Constant quantizer", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_coder"},
{"aac_pns", "Perceptual Noise Substitution", offsetof(AACEncContext, options.pns), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, AACENC_FLAGS, "aac_pns"},
{"disable", "Disable perceptual noise substitution", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_pns"},
{"enable", "Enable perceptual noise substitution", 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_pns"},
{"aac_is", "Intensity stereo coding", offsetof(AACEncContext, options.intensity_stereo), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, AACENC_FLAGS, "intensity_stereo"},
{"disable", "Disable intensity stereo coding", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, AACENC_FLAGS, "intensity_stereo"},
{"enable", "Enable intensity stereo coding", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, INT_MAX, AACENC_FLAGS, "intensity_stereo"},
{"aac_tns", "Temporal noise shaping", offsetof(AACEncContext, options.tns), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AACENC_FLAGS, "aac_tns"},
{"disable", "Disable temporal noise shaping", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_tns"},
{"enable", "Enable temporal noise shaping", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_tns"},
{"aac_pred", "AAC-Main prediction", offsetof(AACEncContext, options.pred), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, AACENC_FLAGS, "aac_pred"},
{"disable", "Disable AAC-Main prediction", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_pred"},
{"enable", "Enable AAC-Main prediction", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, INT_MAX, AACENC_FLAGS, "aac_pred"},
{"aac_coder", "Coding algorithm", offsetof(AACEncContext, options.coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_TWOLOOP}, 0, AAC_CODER_NB-1, AACENC_FLAGS, "coder"},
{"anmr", "ANMR method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_ANMR}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"},
{"twoloop", "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"},
{"fast", "Constant quantizer", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"},
{"aac_ms", "Force M/S stereo coding", offsetof(AACEncContext, options.mid_side), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AACENC_FLAGS},
{"aac_is", "Intensity stereo coding", offsetof(AACEncContext, options.intensity_stereo), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},
{"aac_pns", "Perceptual noise substitution", offsetof(AACEncContext, options.pns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},
{"aac_tns", "Temporal noise shaping", offsetof(AACEncContext, options.tns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS},
{"aac_ltp", "Long term prediction", offsetof(AACEncContext, options.ltp), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS},
{"aac_pred", "AAC-Main prediction", offsetof(AACEncContext, options.pred), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS},
{NULL}
};
@ -915,6 +1056,11 @@ static const AVClass aacenc_class = {
LIBAVUTIL_VERSION_INT,
};
static const AVCodecDefault aac_encode_defaults[] = {
{ "b", "0" },
{ NULL }
};
AVCodec ff_aac_encoder = {
.name = "aac",
.long_name = NULL_IF_CONFIG_SMALL("AAC (Advanced Audio Coding)"),
@ -924,9 +1070,10 @@ AVCodec ff_aac_encoder = {
.init = aac_encode_init,
.encode2 = aac_encode_frame,
.close = aac_encode_end,
.defaults = aac_encode_defaults,
.supported_samplerates = mpeg4audio_sample_rates,
.capabilities = AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_DELAY |
AV_CODEC_CAP_EXPERIMENTAL,
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
.capabilities = AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_DELAY,
.sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE },
.priv_class = &aacenc_class,

View File

@ -23,6 +23,7 @@
#define AVCODEC_AACENC_H
#include "libavutil/float_dsp.h"
#include "libavutil/lfg.h"
#include "avcodec.h"
#include "put_bits.h"
@ -33,8 +34,7 @@
#include "lpc.h"
typedef enum AACCoder {
AAC_CODER_FAAC = 0,
AAC_CODER_ANMR,
AAC_CODER_ANMR = 0,
AAC_CODER_TWOLOOP,
AAC_CODER_FAST,
@ -42,11 +42,12 @@ typedef enum AACCoder {
}AACCoder;
typedef struct AACEncOptions {
int stereo_mode;
int aac_coder;
int coder;
int pns;
int tns;
int ltp;
int pred;
int mid_side;
int intensity_stereo;
} AACEncOptions;
@ -60,13 +61,19 @@ typedef struct AACCoefficientsEncoder {
void (*quantize_and_encode_band)(struct AACEncContext *s, PutBitContext *pb, const float *in, float *out, int size,
int scale_idx, int cb, const float lambda, int rtz);
void (*encode_tns_info)(struct AACEncContext *s, SingleChannelElement *sce);
void (*encode_ltp_info)(struct AACEncContext *s, SingleChannelElement *sce, int common_window);
void (*encode_main_pred)(struct AACEncContext *s, SingleChannelElement *sce);
void (*adjust_common_prediction)(struct AACEncContext *s, ChannelElement *cpe);
void (*adjust_common_pred)(struct AACEncContext *s, ChannelElement *cpe);
void (*adjust_common_ltp)(struct AACEncContext *s, ChannelElement *cpe);
void (*apply_main_pred)(struct AACEncContext *s, SingleChannelElement *sce);
void (*apply_tns_filt)(struct AACEncContext *s, SingleChannelElement *sce);
void (*update_ltp)(struct AACEncContext *s, SingleChannelElement *sce);
void (*ltp_insert_new_frame)(struct AACEncContext *s);
void (*set_special_band_scalefactors)(struct AACEncContext *s, SingleChannelElement *sce);
void (*search_for_pns)(struct AACEncContext *s, AVCodecContext *avctx, SingleChannelElement *sce);
void (*mark_pns)(struct AACEncContext *s, AVCodecContext *avctx, SingleChannelElement *sce);
void (*search_for_tns)(struct AACEncContext *s, SingleChannelElement *sce);
void (*search_for_ltp)(struct AACEncContext *s, SingleChannelElement *sce, int common_window);
void (*search_for_ms)(struct AACEncContext *s, ChannelElement *cpe);
void (*search_for_is)(struct AACEncContext *s, AVCodecContext *avctx, ChannelElement *cpe);
void (*search_for_pred)(struct AACEncContext *s, SingleChannelElement *sce);
@ -74,6 +81,15 @@ typedef struct AACCoefficientsEncoder {
extern AACCoefficientsEncoder ff_aac_coders[];
typedef struct AACQuantizeBandCostCacheEntry {
float rd;
float energy;
int bits; ///< -1 means uninitialized entry
char cb;
char rtz;
char padding[2]; ///< Keeps the entry size a multiple of 32 bits
} AACQuantizeBandCostCacheEntry;
/**
* AAC encoder context
*/
@ -84,7 +100,8 @@ typedef struct AACEncContext {
FFTContext mdct1024; ///< long (1024 samples) frame transform context
FFTContext mdct128; ///< short (128 samples) frame transform context
AVFloatDSPContext *fdsp;
float *planar_samples[6]; ///< saved preprocessed input
AVLFG lfg; ///< PRNG needed for PNS
float *planar_samples[8]; ///< saved preprocessed input
int profile; ///< copied from avctx
LPCContext lpc; ///< used by TNS
@ -96,18 +113,28 @@ typedef struct AACEncContext {
FFPsyContext psy;
struct FFPsyPreprocessContext* psypp;
AACCoefficientsEncoder *coder;
int cur_channel;
int cur_channel; ///< current channel for coder context
int last_frame;
int random_state;
float lambda;
int last_frame_pb_count; ///< number of bits for the previous frame
float lambda_sum; ///< sum(lambda), for Qvg reporting
int lambda_count; ///< count(lambda), for Qvg reporting
enum RawDataBlockType cur_type; ///< channel group type cur_channel belongs to
AudioFrameQueue afq;
DECLARE_ALIGNED(16, int, qcoefs)[96]; ///< quantized coefficients
DECLARE_ALIGNED(32, float, scoefs)[1024]; ///< scaled coefficients
AACQuantizeBandCostCacheEntry quantize_band_cost_cache[256][128]; ///< memoization area for quantize_band_cost
struct {
float *samples;
} buffer;
} AACEncContext;
void ff_aac_coder_init_mips(AACEncContext *c);
void ff_quantize_band_cost_cache_init(struct AACEncContext *s);
#endif /* AVCODEC_AACENC_H */

View File

@ -45,11 +45,16 @@ struct AACISError ff_aac_is_encoding_err(AACEncContext *s, ChannelElement *cpe,
float dist1 = 0.0f, dist2 = 0.0f;
struct AACISError is_error = {0};
if (ener01 <= 0 || ener0 <= 0) {
is_error.pass = 0;
return is_error;
}
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];
int is_band_type, is_sf_idx = FFMAX(1, sce0->sf_idx[(w+w2)*16+g]-4);
float e01_34 = phase*pow(ener1/ener0, 3.0/4.0);
int is_band_type, is_sf_idx = FFMAX(1, sce0->sf_idx[w*16+g]-4);
float e01_34 = phase*pos_pow34(ener1/ener0);
float maxval, dist_spec_err = 0.0f;
float minthr = FFMIN(band0->threshold, band1->threshold);
for (i = 0; i < sce0->ics.swb_sizes[g]; i++)
@ -61,17 +66,17 @@ struct AACISError ff_aac_is_encoding_err(AACEncContext *s, ChannelElement *cpe,
is_band_type = find_min_book(maxval, is_sf_idx);
dist1 += quantize_band_cost(s, &L[start + (w+w2)*128], L34,
sce0->ics.swb_sizes[g],
sce0->sf_idx[(w+w2)*16+g],
sce0->band_type[(w+w2)*16+g],
s->lambda / band0->threshold, INFINITY, NULL, 0);
sce0->sf_idx[w*16+g],
sce0->band_type[w*16+g],
s->lambda / band0->threshold, INFINITY, NULL, NULL, 0);
dist1 += quantize_band_cost(s, &R[start + (w+w2)*128], R34,
sce1->ics.swb_sizes[g],
sce1->sf_idx[(w+w2)*16+g],
sce1->band_type[(w+w2)*16+g],
s->lambda / band1->threshold, INFINITY, NULL, 0);
sce1->sf_idx[w*16+g],
sce1->band_type[w*16+g],
s->lambda / band1->threshold, INFINITY, NULL, NULL, 0);
dist2 += quantize_band_cost(s, IS, I34, sce0->ics.swb_sizes[g],
is_sf_idx, is_band_type,
s->lambda / minthr, INFINITY, NULL, 0);
s->lambda / minthr, INFINITY, NULL, NULL, 0);
for (i = 0; i < sce0->ics.swb_sizes[g]; i++) {
dist_spec_err += (L34[i] - I34[i])*(L34[i] - I34[i]);
dist_spec_err += (R34[i] - I34[i]*e01_34)*(R34[i] - I34[i]*e01_34);
@ -82,9 +87,10 @@ struct AACISError ff_aac_is_encoding_err(AACEncContext *s, ChannelElement *cpe,
is_error.pass = dist2 <= dist1;
is_error.phase = phase;
is_error.error = fabsf(dist1 - dist2);
is_error.error = dist2 - dist1;
is_error.dist1 = dist1;
is_error.dist2 = dist2;
is_error.ener01 = ener01;
return is_error;
}
@ -93,42 +99,58 @@ void ff_aac_search_for_is(AACEncContext *s, AVCodecContext *avctx, ChannelElemen
{
SingleChannelElement *sce0 = &cpe->ch[0];
SingleChannelElement *sce1 = &cpe->ch[1];
int start = 0, count = 0, w, w2, g, i;
int start = 0, count = 0, w, w2, g, i, prev_sf1 = -1, prev_bt = -1, prev_is = 0;
const float freq_mult = avctx->sample_rate/(1024.0f/sce0->ics.num_windows)/2.0f;
uint8_t nextband1[128];
if (!cpe->common_window)
return;
/** Scout out next nonzero bands */
ff_init_nextband_map(sce1, nextband1);
for (w = 0; w < sce0->ics.num_windows; w += sce0->ics.group_len[w]) {
start = 0;
for (g = 0; g < sce0->ics.num_swb; g++) {
if (start*freq_mult > INT_STEREO_LOW_LIMIT*(s->lambda/170.0f) &&
cpe->ch[0].band_type[w*16+g] != NOISE_BT && !cpe->ch[0].zeroes[w*16+g] &&
cpe->ch[1].band_type[w*16+g] != NOISE_BT && !cpe->ch[1].zeroes[w*16+g]) {
float ener0 = 0.0f, ener1 = 0.0f, ener01 = 0.0f;
struct AACISError ph_err1, ph_err2, *erf;
cpe->ch[1].band_type[w*16+g] != NOISE_BT && !cpe->ch[1].zeroes[w*16+g] &&
ff_sfdelta_can_remove_band(sce1, nextband1, prev_sf1, w*16+g)) {
float ener0 = 0.0f, ener1 = 0.0f, ener01 = 0.0f, ener01p = 0.0f;
struct AACISError ph_err1, ph_err2, *best;
for (w2 = 0; w2 < sce0->ics.group_len[w]; w2++) {
for (i = 0; i < sce0->ics.swb_sizes[g]; i++) {
float coef0 = sce0->pcoeffs[start+(w+w2)*128+i];
float coef1 = sce1->pcoeffs[start+(w+w2)*128+i];
float coef0 = sce0->coeffs[start+(w+w2)*128+i];
float coef1 = sce1->coeffs[start+(w+w2)*128+i];
ener0 += coef0*coef0;
ener1 += coef1*coef1;
ener01 += (coef0 + coef1)*(coef0 + coef1);
ener01p += (coef0 - coef1)*(coef0 - coef1);
}
}
ph_err1 = ff_aac_is_encoding_err(s, cpe, start, w, g,
ener0, ener1, ener01, 0, -1);
ener0, ener1, ener01p, 0, -1);
ph_err2 = ff_aac_is_encoding_err(s, cpe, start, w, g,
ener0, ener1, ener01, 0, +1);
erf = ph_err1.error < ph_err2.error ? &ph_err1 : &ph_err2;
if (erf->pass) {
best = (ph_err1.pass && ph_err1.error < ph_err2.error) ? &ph_err1 : &ph_err2;
if (best->pass) {
cpe->is_mask[w*16+g] = 1;
cpe->ch[0].is_ener[w*16+g] = sqrt(ener0/ener01);
cpe->ms_mask[w*16+g] = 0;
cpe->ch[0].is_ener[w*16+g] = sqrt(ener0 / best->ener01);
cpe->ch[1].is_ener[w*16+g] = ener0/ener1;
cpe->ch[1].band_type[w*16+g] = erf->phase ? INTENSITY_BT : INTENSITY_BT2;
cpe->ch[1].band_type[w*16+g] = (best->phase > 0) ? INTENSITY_BT : INTENSITY_BT2;
if (prev_is && prev_bt != cpe->ch[1].band_type[w*16+g]) {
/** Flip M/S mask and pick the other CB, since it encodes more efficiently */
cpe->ms_mask[w*16+g] = 1;
cpe->ch[1].band_type[w*16+g] = (best->phase > 0) ? INTENSITY_BT2 : INTENSITY_BT;
}
prev_bt = cpe->ch[1].band_type[w*16+g];
count++;
}
}
if (!sce1->zeroes[w*16+g] && sce1->band_type[w*16+g] < RESERVED_BT)
prev_sf1 = sce1->sf_idx[w*16+g];
prev_is = cpe->is_mask[w*16+g];
start += sce0->ics.swb_sizes[g];
}
}

View File

@ -39,6 +39,7 @@ struct AACISError {
float error; /* fabs(dist1 - dist2) */
float dist1; /* From original coeffs */
float dist2; /* From IS'd coeffs */
float ener01;
};
struct AACISError ff_aac_is_encoding_err(AACEncContext *s, ChannelElement *cpe,

236
libavcodec/aacenc_ltp.c Normal file
View File

@ -0,0 +1,236 @@
/*
* AAC encoder long term prediction extension
* Copyright (C) 2015 Rostislav Pehlivanov
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* AAC encoder long term prediction extension
* @author Rostislav Pehlivanov ( atomnuker gmail com )
*/
#include "aacenc_ltp.h"
#include "aacenc_quantization.h"
#include "aacenc_utils.h"
/**
* Encode LTP data.
*/
void ff_aac_encode_ltp_info(AACEncContext *s, SingleChannelElement *sce,
int common_window)
{
int i;
IndividualChannelStream *ics = &sce->ics;
if (s->profile != FF_PROFILE_AAC_LTP || !ics->predictor_present)
return;
if (common_window)
put_bits(&s->pb, 1, 0);
put_bits(&s->pb, 1, ics->ltp.present);
if (!ics->ltp.present)
return;
put_bits(&s->pb, 11, ics->ltp.lag);
put_bits(&s->pb, 3, ics->ltp.coef_idx);
for (i = 0; i < FFMIN(ics->max_sfb, MAX_LTP_LONG_SFB); i++)
put_bits(&s->pb, 1, ics->ltp.used[i]);
}
void ff_aac_ltp_insert_new_frame(AACEncContext *s)
{
int i, ch, tag, chans, cur_channel, start_ch = 0;
ChannelElement *cpe;
SingleChannelElement *sce;
for (i = 0; i < s->chan_map[0]; i++) {
cpe = &s->cpe[i];
tag = s->chan_map[i+1];
chans = tag == TYPE_CPE ? 2 : 1;
for (ch = 0; ch < chans; ch++) {
sce = &cpe->ch[ch];
cur_channel = start_ch + ch;
/* New sample + overlap */
memcpy(&sce->ltp_state[0], &sce->ltp_state[1024], 1024*sizeof(sce->ltp_state[0]));
memcpy(&sce->ltp_state[1024], &s->planar_samples[cur_channel][2048], 1024*sizeof(sce->ltp_state[0]));
memcpy(&sce->ltp_state[2048], &sce->ret_buf[0], 1024*sizeof(sce->ltp_state[0]));
sce->ics.ltp.lag = 0;
}
start_ch += chans;
}
}
static void get_lag(float *buf, const float *new, LongTermPrediction *ltp)
{
int i, j, lag, max_corr = 0;
float max_ratio;
for (i = 0; i < 2048; i++) {
float corr, s0 = 0.0f, s1 = 0.0f;
const int start = FFMAX(0, i - 1024);
for (j = start; j < 2048; j++) {
const int idx = j - i + 1024;
s0 += new[j]*buf[idx];
s1 += buf[idx]*buf[idx];
}
corr = s1 > 0.0f ? s0/sqrt(s1) : 0.0f;
if (corr > max_corr) {
max_corr = corr;
lag = i;
max_ratio = corr/(2048-start);
}
}
ltp->lag = FFMAX(av_clip_uintp2(lag, 11), 0);
ltp->coef_idx = quant_array_idx(max_ratio, ltp_coef, 8);
ltp->coef = ltp_coef[ltp->coef_idx];
}
static void generate_samples(float *buf, LongTermPrediction *ltp)
{
int i, samples_num = 2048;
if (!ltp->lag) {
ltp->present = 0;
return;
} else if (ltp->lag < 1024) {
samples_num = ltp->lag + 1024;
}
for (i = 0; i < samples_num; i++)
buf[i] = ltp->coef*buf[i + 2048 - ltp->lag];
memset(&buf[i], 0, (2048 - i)*sizeof(float));
}
/**
* Process LTP parameters
* @see Patent WO2006070265A1
*/
void ff_aac_update_ltp(AACEncContext *s, SingleChannelElement *sce)
{
float *pred_signal = &sce->ltp_state[0];
const float *samples = &s->planar_samples[s->cur_channel][1024];
if (s->profile != FF_PROFILE_AAC_LTP)
return;
/* Calculate lag */
get_lag(pred_signal, samples, &sce->ics.ltp);
generate_samples(pred_signal, &sce->ics.ltp);
}
void ff_aac_adjust_common_ltp(AACEncContext *s, ChannelElement *cpe)
{
int sfb, count = 0;
SingleChannelElement *sce0 = &cpe->ch[0];
SingleChannelElement *sce1 = &cpe->ch[1];
if (!cpe->common_window ||
sce0->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE ||
sce1->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
sce0->ics.ltp.present = 0;
return;
}
for (sfb = 0; sfb < FFMIN(sce0->ics.max_sfb, MAX_LTP_LONG_SFB); sfb++) {
int sum = sce0->ics.ltp.used[sfb] + sce1->ics.ltp.used[sfb];
if (sum != 2) {
sce0->ics.ltp.used[sfb] = 0;
} else if (sum == 2) {
count++;
}
}
sce0->ics.ltp.present = !!count;
sce0->ics.predictor_present = !!count;
}
/**
* Mark LTP sfb's
*/
void ff_aac_search_for_ltp(AACEncContext *s, SingleChannelElement *sce,
int common_window)
{
int w, g, w2, i, start = 0, count = 0;
int saved_bits = -(15 + FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB));
float *C34 = &s->scoefs[128*0], *PCD = &s->scoefs[128*1];
float *PCD34 = &s->scoefs[128*2];
const int max_ltp = FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB);
if (sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE) {
if (sce->ics.ltp.lag) {
memset(&sce->ltp_state[0], 0, 3072*sizeof(sce->ltp_state[0]));
memset(&sce->ics.ltp, 0, sizeof(LongTermPrediction));
}
return;
}
if (!sce->ics.ltp.lag || s->lambda > 120.0f)
return;
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
start = 0;
for (g = 0; g < sce->ics.num_swb; g++) {
int bits1 = 0, bits2 = 0;
float dist1 = 0.0f, dist2 = 0.0f;
if (w*16+g > max_ltp) {
start += sce->ics.swb_sizes[g];
continue;
}
for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
int bits_tmp1, bits_tmp2;
FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g];
for (i = 0; i < sce->ics.swb_sizes[g]; i++)
PCD[i] = sce->coeffs[start+(w+w2)*128+i] - sce->lcoeffs[start+(w+w2)*128+i];
abs_pow34_v(C34, &sce->coeffs[start+(w+w2)*128], sce->ics.swb_sizes[g]);
abs_pow34_v(PCD34, PCD, sce->ics.swb_sizes[g]);
dist1 += quantize_band_cost(s, &sce->coeffs[start+(w+w2)*128], C34, sce->ics.swb_sizes[g],
sce->sf_idx[(w+w2)*16+g], sce->band_type[(w+w2)*16+g],
s->lambda/band->threshold, INFINITY, &bits_tmp1, NULL, 0);
dist2 += quantize_band_cost(s, PCD, PCD34, sce->ics.swb_sizes[g],
sce->sf_idx[(w+w2)*16+g],
sce->band_type[(w+w2)*16+g],
s->lambda/band->threshold, INFINITY, &bits_tmp2, NULL, 0);
bits1 += bits_tmp1;
bits2 += bits_tmp2;
}
if (dist2 < dist1 && bits2 < bits1) {
for (w2 = 0; w2 < sce->ics.group_len[w]; w2++)
for (i = 0; i < sce->ics.swb_sizes[g]; i++)
sce->coeffs[start+(w+w2)*128+i] -= sce->lcoeffs[start+(w+w2)*128+i];
sce->ics.ltp.used[w*16+g] = 1;
saved_bits += bits1 - bits2;
count++;
}
start += sce->ics.swb_sizes[g];
}
}
sce->ics.ltp.present = !!count && (saved_bits >= 0);
sce->ics.predictor_present = !!sce->ics.ltp.present;
/* Reset any marked sfbs */
if (!sce->ics.ltp.present && !!count) {
for (w = 0; w < sce->ics.num_windows; w += sce->ics.group_len[w]) {
start = 0;
for (g = 0; g < sce->ics.num_swb; g++) {
if (sce->ics.ltp.used[w*16+g]) {
for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
for (i = 0; i < sce->ics.swb_sizes[g]; i++) {
sce->coeffs[start+(w+w2)*128+i] += sce->lcoeffs[start+(w+w2)*128+i];
}
}
}
start += sce->ics.swb_sizes[g];
}
}
}
}

41
libavcodec/aacenc_ltp.h Normal file
View File

@ -0,0 +1,41 @@
/*
* AAC encoder long term prediction extension
* Copyright (C) 2015 Rostislav Pehlivanov
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* AAC encoder long term prediction extension
* @author Rostislav Pehlivanov ( atomnuker gmail com )
*/
#ifndef AVCODEC_AACENC_LTP_H
#define AVCODEC_AACENC_LTP_H
#include "aacenc.h"
void ff_aac_encode_ltp_info(AACEncContext *s, SingleChannelElement *sce,
int common_window);
void ff_aac_update_ltp(AACEncContext *s, SingleChannelElement *sce);
void ff_aac_adjust_common_ltp(AACEncContext *s, ChannelElement *cpe);
void ff_aac_ltp_insert_new_frame(AACEncContext *s);
void ff_aac_search_for_ltp(AACEncContext *s, SingleChannelElement *sce,
int common_window);
#endif /* AVCODEC_AACENC_LTP_H */

View File

@ -21,7 +21,7 @@
/**
* @file
* AAC encoder Intensity Stereo
* AAC encoder main-type prediction
* @author Rostislav Pehlivanov ( atomnuker gmail com )
*/
@ -148,7 +148,7 @@ static inline int update_counters(IndividualChannelStream *ics, int inc)
return 0;
}
void ff_aac_adjust_common_prediction(AACEncContext *s, ChannelElement *cpe)
void ff_aac_adjust_common_pred(AACEncContext *s, ChannelElement *cpe)
{
int start, w, w2, g, i, count = 0;
SingleChannelElement *sce0 = &cpe->ch[0];
@ -257,19 +257,23 @@ void ff_aac_search_for_pred(AACEncContext *s, SingleChannelElement *sce)
for (sfb = PRED_SFB_START; sfb < pmax; sfb++) {
int cost1, cost2, cb_p;
float dist1, dist2, dist_spec_err = 0.0f;
const int cb_n = sce->band_type[sfb];
const int cb_n = sce->zeroes[sfb] ? 0 : sce->band_type[sfb];
const int cb_min = sce->zeroes[sfb] ? 0 : 1;
const int cb_max = sce->zeroes[sfb] ? 0 : RESERVED_BT;
const int start_coef = sce->ics.swb_offset[sfb];
const int num_coeffs = sce->ics.swb_offset[sfb + 1] - start_coef;
const FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[sfb];
if (start_coef + num_coeffs > MAX_PREDICTORS)
if (start_coef + num_coeffs > MAX_PREDICTORS ||
(s->cur_channel && sce->band_type[sfb] >= INTENSITY_BT2) ||
sce->band_type[sfb] == NOISE_BT)
continue;
/* Normal coefficients */
abs_pow34_v(O34, &sce->coeffs[start_coef], num_coeffs);
dist1 = quantize_and_encode_band_cost(s, NULL, &sce->coeffs[start_coef], NULL,
O34, num_coeffs, sce->sf_idx[sfb],
cb_n, s->lambda / band->threshold, INFINITY, &cost1, 0);
cb_n, s->lambda / band->threshold, INFINITY, &cost1, NULL, 0);
cost_coeffs += cost1;
/* Encoded coefficients - needed for #bits, band type and quant. error */
@ -277,24 +281,24 @@ void ff_aac_search_for_pred(AACEncContext *s, SingleChannelElement *sce)
SENT[i] = sce->coeffs[start_coef + i] - sce->prcoeffs[start_coef + i];
abs_pow34_v(S34, SENT, num_coeffs);
if (cb_n < RESERVED_BT)
cb_p = find_min_book(find_max_val(1, num_coeffs, S34), sce->sf_idx[sfb]);
cb_p = av_clip(find_min_book(find_max_val(1, num_coeffs, S34), sce->sf_idx[sfb]), cb_min, cb_max);
else
cb_p = cb_n;
quantize_and_encode_band_cost(s, NULL, SENT, QERR, S34, num_coeffs,
sce->sf_idx[sfb], cb_p, s->lambda / band->threshold, INFINITY,
&cost2, 0);
&cost2, NULL, 0);
/* Reconstructed coefficients - needed for distortion measurements */
for (i = 0; i < num_coeffs; i++)
sce->prcoeffs[start_coef + i] += QERR[i] != 0.0f ? (sce->prcoeffs[start_coef + i] - QERR[i]) : 0.0f;
abs_pow34_v(P34, &sce->prcoeffs[start_coef], num_coeffs);
if (cb_n < RESERVED_BT)
cb_p = find_min_book(find_max_val(1, num_coeffs, P34), sce->sf_idx[sfb]);
cb_p = av_clip(find_min_book(find_max_val(1, num_coeffs, P34), sce->sf_idx[sfb]), cb_min, cb_max);
else
cb_p = cb_n;
dist2 = quantize_and_encode_band_cost(s, NULL, &sce->prcoeffs[start_coef], NULL,
P34, num_coeffs, sce->sf_idx[sfb],
cb_p, s->lambda / band->threshold, INFINITY, NULL, 0);
cb_p, s->lambda / band->threshold, INFINITY, NULL, NULL, 0);
for (i = 0; i < num_coeffs; i++)
dist_spec_err += (O34[i] - P34[i])*(O34[i] - P34[i]);
dist_spec_err *= s->lambda / band->threshold;
@ -331,7 +335,8 @@ void ff_aac_encode_main_pred(AACEncContext *s, SingleChannelElement *sce)
IndividualChannelStream *ics = &sce->ics;
const int pmax = FFMIN(ics->max_sfb, ff_aac_pred_sfb_max[s->samplerate_index]);
if (!ics->predictor_present)
if (s->profile != FF_PROFILE_AAC_MAIN ||
!ics->predictor_present)
return;
put_bits(&s->pb, 1, !!ics->predictor_reset_group);

View File

@ -21,7 +21,7 @@
/**
* @file
* AAC encoder main prediction
* AAC encoder main-type prediction
* @author Rostislav Pehlivanov ( atomnuker gmail com )
*/
@ -40,7 +40,7 @@
#define PRED_SFB_START 10
void ff_aac_apply_main_pred(AACEncContext *s, SingleChannelElement *sce);
void ff_aac_adjust_common_prediction(AACEncContext *s, ChannelElement *cpe);
void ff_aac_adjust_common_pred(AACEncContext *s, ChannelElement *cpe);
void ff_aac_search_for_pred(AACEncContext *s, SingleChannelElement *sce);
void ff_aac_encode_main_pred(AACEncContext *s, SingleChannelElement *sce);

View File

@ -1,5 +1,5 @@
/*
* AAC encoder intensity stereo
* AAC encoder quantizer
* Copyright (C) 2015 Rostislav Pehlivanov
*
* This file is part of FFmpeg.
@ -43,7 +43,7 @@ static av_always_inline float quantize_and_encode_band_cost_template(
PutBitContext *pb, const float *in, float *out,
const float *scaled, int size, int scale_idx,
int cb, const float lambda, const float uplim,
int *bits, int BT_ZERO, int BT_UNSIGNED,
int *bits, float *energy, int BT_ZERO, int BT_UNSIGNED,
int BT_PAIR, int BT_ESC, int BT_NOISE, int BT_STEREO,
const float ROUNDING)
{
@ -54,6 +54,7 @@ static av_always_inline float quantize_and_encode_band_cost_template(
const float CLIPPED_ESCAPE = 165140.0f*IQ;
int i, j;
float cost = 0;
float qenergy = 0;
const int dim = BT_PAIR ? 2 : 4;
int resbits = 0;
int off;
@ -63,6 +64,8 @@ static av_always_inline float quantize_and_encode_band_cost_template(
cost += in[i]*in[i];
if (bits)
*bits = 0;
if (energy)
*energy = qenergy;
if (out) {
for (i = 0; i < size; i += dim)
for (j = 0; j < dim; j++)
@ -113,11 +116,13 @@ static av_always_inline float quantize_and_encode_band_cost_template(
out[i+j] = in[i+j] >= 0 ? quantized : -quantized;
if (vec[j] != 0.0f)
curbits++;
qenergy += quantized*quantized;
rd += di*di;
}
} else {
for (j = 0; j < dim; j++) {
quantized = vec[j]*IQ;
qenergy += quantized*quantized;
if (out)
out[i+j] = quantized;
rd += (in[i+j] - quantized)*(in[i+j] - quantized);
@ -149,6 +154,8 @@ static av_always_inline float quantize_and_encode_band_cost_template(
if (bits)
*bits = resbits;
if (energy)
*energy = qenergy;
return cost;
}
@ -156,7 +163,7 @@ static inline float quantize_and_encode_band_cost_NONE(struct AACEncContext *s,
const float *in, float *quant, const float *scaled,
int size, int scale_idx, int cb,
const float lambda, const float uplim,
int *bits) {
int *bits, float *energy) {
av_assert0(0);
return 0.0f;
}
@ -167,10 +174,10 @@ static float quantize_and_encode_band_cost_ ## NAME(
PutBitContext *pb, const float *in, float *quant, \
const float *scaled, int size, int scale_idx, \
int cb, const float lambda, const float uplim, \
int *bits) { \
int *bits, float *energy) { \
return quantize_and_encode_band_cost_template( \
s, pb, in, quant, scaled, size, scale_idx, \
BT_ESC ? ESC_BT : cb, lambda, uplim, bits, \
BT_ESC ? ESC_BT : cb, lambda, uplim, bits, energy, \
BT_ZERO, BT_UNSIGNED, BT_PAIR, BT_ESC, BT_NOISE, BT_STEREO, \
ROUNDING); \
}
@ -190,7 +197,7 @@ static float (*const quantize_and_encode_band_cost_arr[])(
PutBitContext *pb, const float *in, float *quant,
const float *scaled, int size, int scale_idx,
int cb, const float lambda, const float uplim,
int *bits) = {
int *bits, float *energy) = {
quantize_and_encode_band_cost_ZERO,
quantize_and_encode_band_cost_SQUAD,
quantize_and_encode_band_cost_SQUAD,
@ -214,7 +221,7 @@ static float (*const quantize_and_encode_band_cost_rtz_arr[])(
PutBitContext *pb, const float *in, float *quant,
const float *scaled, int size, int scale_idx,
int cb, const float lambda, const float uplim,
int *bits) = {
int *bits, float *energy) = {
quantize_and_encode_band_cost_ZERO,
quantize_and_encode_band_cost_SQUAD,
quantize_and_encode_band_cost_SQUAD,
@ -235,18 +242,32 @@ static float (*const quantize_and_encode_band_cost_rtz_arr[])(
#define quantize_and_encode_band_cost( \
s, pb, in, quant, scaled, size, scale_idx, cb, \
lambda, uplim, bits, rtz) \
lambda, uplim, bits, energy, rtz) \
((rtz) ? quantize_and_encode_band_cost_rtz_arr : quantize_and_encode_band_cost_arr)[cb]( \
s, pb, in, quant, scaled, size, scale_idx, cb, \
lambda, uplim, bits)
lambda, uplim, bits, energy)
static inline 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, int rtz)
int *bits, float *energy, int rtz)
{
return quantize_and_encode_band_cost(s, NULL, in, NULL, scaled, size, scale_idx,
cb, lambda, uplim, bits, rtz);
cb, lambda, uplim, bits, energy, rtz);
}
static inline int 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, float *energy, int rtz)
{
int auxbits;
quantize_and_encode_band_cost(s, NULL, in, NULL, scaled, size, scale_idx,
cb, 0.0f, uplim, &auxbits, energy, rtz);
if (bits) {
*bits = auxbits;
}
return auxbits;
}
static inline void quantize_and_encode_band(struct AACEncContext *s, PutBitContext *pb,
@ -254,7 +275,9 @@ static inline void quantize_and_encode_band(struct AACEncContext *s, PutBitConte
int cb, const float lambda, int rtz)
{
quantize_and_encode_band_cost(s, pb, in, out, NULL, size, scale_idx, cb, lambda,
INFINITY, NULL, rtz);
INFINITY, NULL, NULL, rtz);
}
#include "aacenc_quantization_misc.h"
#endif /* AVCODEC_AACENC_QUANTIZATION_H */

View File

@ -0,0 +1,52 @@
/*
* AAC encoder quantization
* Copyright (C) 2015 Claudio Freire
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* AAC encoder quantization misc reusable function templates
* @author Claudio Freire ( klaussfreire gmail com )
*/
#ifndef AVCODEC_AACENC_QUANTIZATION_MISC_H
#define AVCODEC_AACENC_QUANTIZATION_MISC_H
static inline float quantize_band_cost_cached(struct AACEncContext *s, int w, int g, const float *in,
const float *scaled, int size, int scale_idx,
int cb, const float lambda, const float uplim,
int *bits, float *energy, int rtz)
{
AACQuantizeBandCostCacheEntry *entry;
av_assert1(scale_idx >= 0 && scale_idx < 256);
entry = &s->quantize_band_cost_cache[scale_idx][w*16+g];
if (entry->bits < 0 || entry->cb != cb || entry->rtz != rtz) {
entry->rd = quantize_band_cost(s, in, scaled, size, scale_idx,
cb, lambda, uplim, &entry->bits, &entry->energy, rtz);
entry->cb = cb;
entry->rtz = rtz;
}
if (bits)
*bits = entry->bits;
if (energy)
*energy = entry->energy;
return entry->rd;
}
#endif /* AVCODEC_AACENC_QUANTIZATION_MISC_H */

View File

@ -25,62 +25,79 @@
* @author Rostislav Pehlivanov ( atomnuker gmail com )
*/
#include "libavutil/libm.h"
#include "aacenc.h"
#include "aacenc_tns.h"
#include "aactab.h"
#include "aacenc_utils.h"
#include "aacenc_quantization.h"
/* Could be set to 3 to save an additional bit at the cost of little quality */
#define TNS_Q_BITS 4
/* Coefficient resolution in short windows */
#define TNS_Q_BITS_IS8 4
/* We really need the bits we save here elsewhere */
#define TNS_ENABLE_COEF_COMPRESSION
/* TNS will only be used if the LPC gain is within these margins */
#define TNS_GAIN_THRESHOLD_LOW 1.4f
#define TNS_GAIN_THRESHOLD_HIGH 1.16f*TNS_GAIN_THRESHOLD_LOW
static inline int compress_coeffs(int *coef, int order, int c_bits)
{
int i;
const int low_idx = c_bits ? 4 : 2;
const int shift_val = c_bits ? 8 : 4;
const int high_idx = c_bits ? 11 : 5;
#ifndef TNS_ENABLE_COEF_COMPRESSION
return 0;
#endif /* TNS_ENABLE_COEF_COMPRESSION */
for (i = 0; i < order; i++)
if (coef[i] >= low_idx && coef[i] <= high_idx)
return 0;
for (i = 0; i < order; i++)
coef[i] -= (coef[i] > high_idx) ? shift_val : 0;
return 1;
}
/**
* Encode TNS data.
* Coefficient compression saves a single bit per coefficient.
* Coefficient compression is simply not lossless as it should be
* on any decoder tested and as such is not active.
*/
void ff_aac_encode_tns_info(AACEncContext *s, SingleChannelElement *sce)
{
uint8_t u_coef;
const uint8_t coef_res = TNS_Q_BITS == 4;
int i, w, filt, coef_len, coef_compress = 0;
const int is8 = sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE;
TemporalNoiseShaping *tns = &sce->tns;
int i, w, filt, coef_compress = 0, coef_len;
const int is8 = sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE;
const int c_bits = is8 ? TNS_Q_BITS_IS8 == 4 : TNS_Q_BITS == 4;
if (!sce->tns.present)
return;
for (i = 0; i < sce->ics.num_windows; i++) {
put_bits(&s->pb, 2 - is8, sce->tns.n_filt[i]);
if (tns->n_filt[i]) {
put_bits(&s->pb, 1, coef_res);
for (filt = 0; filt < tns->n_filt[i]; filt++) {
put_bits(&s->pb, 6 - 2 * is8, tns->length[i][filt]);
put_bits(&s->pb, 5 - 2 * is8, tns->order[i][filt]);
if (tns->order[i][filt]) {
put_bits(&s->pb, 1, !!tns->direction[i][filt]);
put_bits(&s->pb, 1, !!coef_compress);
coef_len = coef_res + 3 - coef_compress;
for (w = 0; w < tns->order[i][filt]; w++) {
u_coef = (tns->coef_idx[i][filt][w])&(~(~0<<coef_len));
put_bits(&s->pb, coef_len, u_coef);
}
}
}
if (!tns->n_filt[i])
continue;
put_bits(&s->pb, 1, c_bits);
for (filt = 0; filt < tns->n_filt[i]; filt++) {
put_bits(&s->pb, 6 - 2 * is8, tns->length[i][filt]);
put_bits(&s->pb, 5 - 2 * is8, tns->order[i][filt]);
if (!tns->order[i][filt])
continue;
put_bits(&s->pb, 1, tns->direction[i][filt]);
coef_compress = compress_coeffs(tns->coef_idx[i][filt],
tns->order[i][filt], c_bits);
put_bits(&s->pb, 1, coef_compress);
coef_len = c_bits + 3 - coef_compress;
for (w = 0; w < tns->order[i][filt]; w++)
put_bits(&s->pb, coef_len, tns->coef_idx[i][filt][w]);
}
}
}
static inline void quantize_coefs(double *coef, int *idx, float *lpc, int order)
{
int i;
uint8_t u_coef;
const float *quant_arr = tns_tmp2_map[TNS_Q_BITS == 4];
const double iqfac_p = ((1 << (TNS_Q_BITS-1)) - 0.5)/(M_PI/2.0);
const double iqfac_m = ((1 << (TNS_Q_BITS-1)) + 0.5)/(M_PI/2.0);
for (i = 0; i < order; i++) {
idx[i] = ceilf(asin(coef[i])*((coef[i] >= 0) ? iqfac_p : iqfac_m));
u_coef = (idx[i])&(~(~0<<TNS_Q_BITS));
lpc[i] = quant_arr[u_coef];
}
}
/* Apply TNS filter */
void ff_aac_apply_tns(AACEncContext *s, SingleChannelElement *sce)
{
@ -114,81 +131,85 @@ void ff_aac_apply_tns(AACEncContext *s, SingleChannelElement *sce)
}
start += w * 128;
// ar filter
for (m = 0; m < size; m++, start += inc)
for (i = 1; i <= FFMIN(m, order); i++)
/* AR filter */
for (m = 0; m < size; m++, start += inc) {
for (i = 1; i <= FFMIN(m, order); i++) {
sce->coeffs[start] += lpc[i-1]*sce->pcoeffs[start - i*inc];
}
}
}
}
}
/*
* c_bits - 1 if 4 bit coefficients, 0 if 3 bit coefficients
*/
static inline void quantize_coefs(double *coef, int *idx, float *lpc, int order,
int c_bits)
{
int i;
const float *quant_arr = tns_tmp2_map[c_bits];
for (i = 0; i < order; i++) {
idx[i] = quant_array_idx(coef[i], quant_arr, c_bits ? 16 : 8);
lpc[i] = quant_arr[idx[i]];
}
}
/*
* 3 bits per coefficient with 8 short windows
*/
void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce)
{
TemporalNoiseShaping *tns = &sce->tns;
int w, w2, g, count = 0;
int w, g, count = 0;
double gain, coefs[MAX_LPC_ORDER];
const int mmm = FFMIN(sce->ics.tns_max_bands, sce->ics.max_sfb);
const int is8 = sce->ics.window_sequence[0] == EIGHT_SHORT_SEQUENCE;
const int c_bits = is8 ? TNS_Q_BITS_IS8 == 4 : TNS_Q_BITS == 4;
const int sfb_start = av_clip(tns_min_sfb[is8][s->samplerate_index], 0, mmm);
const int sfb_end = av_clip(sce->ics.num_swb, 0, mmm);
const int order = is8 ? 7 : s->profile == FF_PROFILE_AAC_LOW ? 12 : TNS_MAX_ORDER;
const int slant = sce->ics.window_sequence[0] == LONG_STOP_SEQUENCE ? 1 :
sce->ics.window_sequence[0] == LONG_START_SEQUENCE ? 0 : 2;
const int sfb_len = sfb_end - sfb_start;
const int coef_len = sce->ics.swb_offset[sfb_end] - sce->ics.swb_offset[sfb_start];
int sfb_start = av_clip(tns_min_sfb[is8][s->samplerate_index], 0, mmm);
int sfb_end = av_clip(sce->ics.num_swb, 0, mmm);
for (w = 0; w < sce->ics.num_windows; w++) {
float e_ratio = 0.0f, threshold = 0.0f, spread = 0.0f, en[2] = {0.0, 0.0f};
double gain = 0.0f, coefs[MAX_LPC_ORDER] = {0};
int coef_start = w*sce->ics.num_swb + sce->ics.swb_offset[sfb_start];
int coef_len = sce->ics.swb_offset[sfb_end] - sce->ics.swb_offset[sfb_start];
for (g = 0; g < sce->ics.num_swb; g++) {
if (w*16+g < sfb_start || w*16+g > sfb_end)
continue;
for (w2 = 0; w2 < sce->ics.group_len[w]; w2++) {
FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[(w+w2)*16+g];
if ((w+w2)*16+g > sfb_start + ((sfb_end - sfb_start)/2))
en[1] += band->energy;
else
en[0] += band->energy;
threshold += band->threshold;
spread += band->spread;
}
}
if (coef_len <= 0 || (sfb_end - sfb_start) <= 0)
continue;
else
e_ratio = en[0]/en[1];
/* LPC */
gain = ff_lpc_calc_ref_coefs_f(&s->lpc, &sce->coeffs[coef_start],
coef_len, order, coefs);
if (gain > TNS_GAIN_THRESHOLD_LOW && gain < TNS_GAIN_THRESHOLD_HIGH &&
(en[0]+en[1]) > TNS_GAIN_THRESHOLD_LOW*threshold &&
spread < TNS_SPREAD_THRESHOLD && order) {
if (is8 || order < 2 || (e_ratio > TNS_E_RATIO_LOW && e_ratio < TNS_E_RATIO_HIGH)) {
tns->n_filt[w] = 1;
for (g = 0; g < tns->n_filt[w]; g++) {
tns->length[w][g] = sfb_end - sfb_start;
tns->direction[w][g] = en[0] < en[1];
tns->order[w][g] = order;
quantize_coefs(coefs, tns->coef_idx[w][g], tns->coef[w][g],
order);
}
} else { /* 2 filters due to energy disbalance */
tns->n_filt[w] = 2;
for (g = 0; g < tns->n_filt[w]; g++) {
tns->direction[w][g] = en[g] < en[!g];
tns->order[w][g] = !g ? order/2 : order - tns->order[w][g-1];
tns->length[w][g] = !g ? (sfb_end - sfb_start)/2 : \
(sfb_end - sfb_start) - tns->length[w][g-1];
quantize_coefs(&coefs[!g ? 0 : order - tns->order[w][g-1]],
tns->coef_idx[w][g], tns->coef[w][g],
tns->order[w][g]);
}
}
count++;
}
if (coef_len <= 0 || sfb_len <= 0) {
sce->tns.present = 0;
return;
}
for (w = 0; w < sce->ics.num_windows; w++) {
float en[2] = {0.0f, 0.0f};
int oc_start = 0, os_start = 0;
int coef_start = sce->ics.swb_offset[sfb_start];
for (g = sfb_start; g < sce->ics.num_swb && g <= sfb_end; g++) {
FFPsyBand *band = &s->psy.ch[s->cur_channel].psy_bands[w*16+g];
if (g > sfb_start + (sfb_len/2))
en[1] += band->energy;
else
en[0] += band->energy;
}
/* LPC */
gain = ff_lpc_calc_ref_coefs_f(&s->lpc, &sce->coeffs[w*128 + coef_start],
coef_len, order, coefs);
if (!order || !isfinite(gain) || gain < TNS_GAIN_THRESHOLD_LOW || gain > TNS_GAIN_THRESHOLD_HIGH)
continue;
tns->n_filt[w] = is8 ? 1 : order != TNS_MAX_ORDER ? 2 : 3;
for (g = 0; g < tns->n_filt[w]; g++) {
tns->direction[w][g] = slant != 2 ? slant : en[g] < en[!g];
tns->order[w][g] = g < tns->n_filt[w] ? order/tns->n_filt[w] : order - oc_start;
tns->length[w][g] = g < tns->n_filt[w] ? sfb_len/tns->n_filt[w] : sfb_len - os_start;
quantize_coefs(&coefs[oc_start], tns->coef_idx[w][g], tns->coef[w][g],
tns->order[w][g], c_bits);
oc_start += tns->order[w][g];
os_start += tns->length[w][g];
}
count++;
}
sce->tns.present = !!count;
}

View File

@ -30,21 +30,6 @@
#include "aacenc.h"
/* Could be set to 3 to save an additional bit at the cost of little quality */
#define TNS_Q_BITS 4
/* TNS will only be used if the LPC gain is within these margins */
#define TNS_GAIN_THRESHOLD_LOW 1.395f
#define TNS_GAIN_THRESHOLD_HIGH 11.19f
/* If the energy ratio between the low SFBs vs the high SFBs is not between
* those two values, use 2 filters instead */
#define TNS_E_RATIO_LOW 0.77
#define TNS_E_RATIO_HIGH 1.23
/* Do not use TNS if the psy band spread is below this value */
#define TNS_SPREAD_THRESHOLD 37.081512f
void ff_aac_encode_tns_info(AACEncContext *s, SingleChannelElement *sce);
void ff_aac_apply_tns(AACEncContext *s, SingleChannelElement *sce);
void ff_aac_search_for_tns(AACEncContext *s, SingleChannelElement *sce);

View File

@ -29,8 +29,8 @@
#define AVCODEC_AACENC_UTILS_H
#include "aac.h"
#include "aac_tablegen_decl.h"
#include "aacenctab.h"
#include "aactab.h"
#define ROUND_STANDARD 0.4054f
#define ROUND_TO_ZERO 0.1054f
@ -45,6 +45,11 @@ static inline void abs_pow34_v(float *out, const float *in, const int size)
}
}
static inline float pos_pow34(float a)
{
return sqrtf(a * sqrtf(a));
}
/**
* Quantize one coefficient.
* @return absolute value of the quantized coefficient
@ -89,16 +94,62 @@ static inline int find_min_book(float maxval, int sf)
float Q34 = sqrtf(Q * sqrtf(Q));
int qmaxval, cb;
qmaxval = maxval * Q34 + C_QUANT;
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;
if (qmaxval >= (FF_ARRAY_ELEMS(aac_maxval_cb)))
cb = 11;
else
cb = aac_maxval_cb[qmaxval];
return cb;
}
static inline float find_form_factor(int group_len, int swb_size, float thresh,
const float *scaled, float nzslope) {
const float iswb_size = 1.0f / swb_size;
const float iswb_sizem1 = 1.0f / (swb_size - 1);
const float ethresh = thresh;
float form = 0.0f, weight = 0.0f;
int w2, i;
for (w2 = 0; w2 < group_len; w2++) {
float e = 0.0f, e2 = 0.0f, var = 0.0f, maxval = 0.0f;
float nzl = 0;
for (i = 0; i < swb_size; i++) {
float s = fabsf(scaled[w2*128+i]);
maxval = FFMAX(maxval, s);
e += s;
e2 += s *= s;
/* We really don't want a hard non-zero-line count, since
* even below-threshold lines do add up towards band spectral power.
* So, fall steeply towards zero, but smoothly
*/
if (s >= ethresh) {
nzl += 1.0f;
} else {
nzl += powf(s / ethresh, nzslope);
}
}
if (e2 > thresh) {
float frm;
e *= iswb_size;
/** compute variance */
for (i = 0; i < swb_size; i++) {
float d = fabsf(scaled[w2*128+i]) - e;
var += d*d;
}
var = sqrtf(var * iswb_sizem1);
e2 *= iswb_size;
frm = e / FFMIN(e+4*var,maxval);
form += e2 * sqrtf(frm) / FFMAX(0.5f,nzl);
weight += e2;
}
}
if (weight > 0) {
return form / weight;
} else {
return 1.0f;
}
}
/** Return the minimum scalefactor where the quantized coef does not clip. */
static inline uint8_t coef2minsf(float coef)
{
@ -128,6 +179,76 @@ static inline int quant_array_idx(const float val, const float *arr, const int n
return index;
}
/**
* approximates exp10f(-3.0f*(0.5f + 0.5f * cosf(FFMIN(b,15.5f) / 15.5f)))
*/
static av_always_inline float bval2bmax(float b)
{
return 0.001f + 0.0035f * (b*b*b) / (15.5f*15.5f*15.5f);
}
/*
* Compute a nextband map to be used with SF delta constraint utilities.
* The nextband array should contain 128 elements, and positions that don't
* map to valid, nonzero bands of the form w*16+g (with w being the initial
* window of the window group, only) are left indetermined.
*/
static inline void ff_init_nextband_map(const SingleChannelElement *sce, uint8_t *nextband)
{
unsigned char prevband = 0;
int w, g;
/** Just a safe default */
for (g = 0; g < 128; g++)
nextband[g] = g;
/** Now really navigate the nonzero band chain */
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->band_type[w*16+g] < RESERVED_BT)
prevband = nextband[prevband] = w*16+g;
}
}
nextband[prevband] = prevband; /* terminate */
}
/*
* Updates nextband to reflect a removed band (equivalent to
* calling ff_init_nextband_map after marking a band as zero)
*/
static inline void ff_nextband_remove(uint8_t *nextband, int prevband, int band)
{
nextband[prevband] = nextband[band];
}
/*
* Checks whether the specified band could be removed without inducing
* scalefactor delta that violates SF delta encoding constraints.
* prev_sf has to be the scalefactor of the previous nonzero, nonspecial
* band, in encoding order, or negative if there was no such band.
*/
static inline int ff_sfdelta_can_remove_band(const SingleChannelElement *sce,
const uint8_t *nextband, int prev_sf, int band)
{
return prev_sf >= 0
&& sce->sf_idx[nextband[band]] >= (prev_sf - SCALE_MAX_DIFF)
&& sce->sf_idx[nextband[band]] <= (prev_sf + SCALE_MAX_DIFF);
}
/*
* Checks whether the specified band's scalefactor could be replaced
* with another one without violating SF delta encoding constraints.
* prev_sf has to be the scalefactor of the previous nonzero, nonsepcial
* band, in encoding order, or negative if there was no such band.
*/
static inline int ff_sfdelta_can_replace(const SingleChannelElement *sce,
const uint8_t *nextband, int prev_sf, int new_sf, int band)
{
return new_sf >= (prev_sf - SCALE_MAX_DIFF)
&& new_sf <= (prev_sf + SCALE_MAX_DIFF)
&& sce->sf_idx[nextband[band]] >= (new_sf - SCALE_MAX_DIFF)
&& sce->sf_idx[nextband[band]] <= (new_sf + SCALE_MAX_DIFF);
}
#define ERROR_IF(cond, ...) \
if (cond) { \
av_log(avctx, AV_LOG_ERROR, __VA_ARGS__); \
@ -139,5 +260,4 @@ static inline int quant_array_idx(const float val, const float *arr, const int n
av_log(avctx, AV_LOG_WARNING, __VA_ARGS__); \
}
#endif /* AVCODEC_AACENC_UTILS_H */

View File

@ -36,7 +36,7 @@
/** Total number of codebooks, including special ones **/
#define CB_TOT_ALL 15
#define AAC_MAX_CHANNELS 6
#define AAC_MAX_CHANNELS 8
extern const uint8_t *ff_aac_swb_size_1024[];
extern const int ff_aac_swb_size_1024_len;
@ -44,13 +44,15 @@ extern const uint8_t *ff_aac_swb_size_128[];
extern const int ff_aac_swb_size_128_len;
/** default channel configurations */
static const uint8_t aac_chan_configs[6][5] = {
{1, TYPE_SCE}, // 1 channel - single channel element
{1, TYPE_CPE}, // 2 channels - channel pair
{2, TYPE_SCE, TYPE_CPE}, // 3 channels - center + stereo
{3, TYPE_SCE, TYPE_CPE, TYPE_SCE}, // 4 channels - front center + stereo + back center
{3, TYPE_SCE, TYPE_CPE, TYPE_CPE}, // 5 channels - front center + stereo + back stereo
{4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_LFE}, // 6 channels - front center + stereo + back stereo + LFE
static const uint8_t aac_chan_configs[AAC_MAX_CHANNELS][6] = {
{1, TYPE_SCE}, // 1 channel - single channel element
{1, TYPE_CPE}, // 2 channels - channel pair
{2, TYPE_SCE, TYPE_CPE}, // 3 channels - center + stereo
{3, TYPE_SCE, TYPE_CPE, TYPE_SCE}, // 4 channels - front center + stereo + back center
{3, TYPE_SCE, TYPE_CPE, TYPE_CPE}, // 5 channels - front center + stereo + back stereo
{4, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_LFE}, // 6 channels - front center + stereo + back stereo + LFE
{0}, // 7 channels - invalid without PCE
{5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_LFE}, // 8 channels - front center + front stereo + side stereo + back stereo + LFE
};
/**
@ -63,6 +65,8 @@ static const uint8_t aac_chan_maps[AAC_MAX_CHANNELS][AAC_MAX_CHANNELS] = {
{ 2, 0, 1, 3 },
{ 2, 0, 1, 3, 4 },
{ 2, 0, 1, 4, 5, 3 },
{ 0 },
{ 2, 0, 1, 6, 7, 4, 5, 3 },
};
/* duplicated from avpriv_mpeg4audio_sample_rates to avoid shared build
@ -110,4 +114,15 @@ static const uint8_t aac_cb_in_map[CB_TOT_ALL+1] = {0,1,2,3,4,5,6,7,8,9,10,11,0,
static const uint8_t aac_cb_range [12] = {0, 3, 3, 3, 3, 9, 9, 8, 8, 13, 13, 17};
static const uint8_t aac_cb_maxval[12] = {0, 1, 1, 2, 2, 4, 4, 7, 7, 12, 12, 16};
static const unsigned char aac_maxval_cb[] = {
0, 1, 3, 5, 5, 7, 7, 7, 9, 9, 9, 9, 9, 11
};
static const int aacenc_profiles[] = {
FF_PROFILE_AAC_MAIN,
FF_PROFILE_AAC_LOW,
FF_PROFILE_AAC_LTP,
FF_PROFILE_MPEG2_AAC_LOW,
};
#endif /* AVCODEC_AACENCTAB_H */

View File

@ -19,8 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_PS_H
#define AVCODEC_PS_H
#ifndef AVCODEC_AACPS_H
#define AVCODEC_AACPS_H
#include <stdint.h>
@ -83,4 +83,4 @@ void AAC_RENAME(ff_ps_ctx_init)(PSContext *ps);
int AAC_RENAME(ff_ps_read_data)(AVCodecContext *avctx, GetBitContext *gb, PSContext *ps, int bits_left);
int AAC_RENAME(ff_ps_apply)(AVCodecContext *avctx, PSContext *ps, INTFLOAT L[2][38][64], INTFLOAT R[2][38][64], int top);
#endif /* AVCODEC_PS_H */
#endif /* AVCODEC_AACPS_H */

View File

@ -23,8 +23,8 @@
*
*/
#ifndef AACPS_FIXED_TABLEGEN_H
#define AACPS_FIXED_TABLEGEN_H
#ifndef AVCODEC_AACPS_FIXED_TABLEGEN_H
#define AVCODEC_AACPS_FIXED_TABLEGEN_H
#include <math.h>
#include <stdint.h>
@ -400,4 +400,4 @@ static void ps_tableinit(void)
}
#endif /* CONFIG_HARDCODED_TABLES */
#endif /* AACPS_FIXED_TABLEGEN_H */
#endif /* AVCODEC_AACPS_FIXED_TABLEGEN_H */

View File

@ -20,8 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AACPS_TABLEGEN_H
#define AACPS_TABLEGEN_H
#ifndef AVCODEC_AACPS_TABLEGEN_H
#define AVCODEC_AACPS_TABLEGEN_H
#include <math.h>
#include <stdint.h>
@ -136,7 +136,7 @@ static av_cold void ps_tableinit(void)
float pd2_im = ipdopd_sin[pd2];
float re_smooth = 0.25f * pd0_re + 0.5f * pd1_re + pd2_re;
float im_smooth = 0.25f * pd0_im + 0.5f * pd1_im + pd2_im;
float pd_mag = 1 / sqrt(im_smooth * im_smooth + re_smooth * re_smooth);
float pd_mag = 1 / hypot(im_smooth, re_smooth);
pd_re_smooth[pd0*64+pd1*8+pd2] = re_smooth * pd_mag;
pd_im_smooth[pd0*64+pd1*8+pd2] = im_smooth * pd_mag;
}
@ -214,4 +214,4 @@ static av_cold void ps_tableinit(void)
}
#endif /* CONFIG_HARDCODED_TABLES */
#endif /* AACPS_TABLEGEN_H */
#endif /* AVCODEC_AACPS_TABLEGEN_H */

View File

@ -26,13 +26,13 @@
#if USE_FIXED
#define TYPE_NAME "int32_t"
#define INT32FLOAT int32_t
typedef int32_t INT32FLOAT;
#define ARRAY_RENAME(x) write_int32_t_ ## x
#define ARRAY_URENAME(x) write_uint32_t_ ## x
#include "aacps_fixed_tablegen.h"
#else
#define TYPE_NAME "float"
#define INT32FLOAT float
typedef float INT32FLOAT;
#define ARRAY_RENAME(x) write_float_ ## x
#define ARRAY_URENAME(x) write_float_ ## x
#include "aacps_tablegen.h"

View File

@ -18,8 +18,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef LIBAVCODEC_AACPSDSP_H
#define LIBAVCODEC_AACPSDSP_H
#ifndef AVCODEC_AACPSDSP_H
#define AVCODEC_AACPSDSP_H
#include "aac_defines.h"
@ -54,4 +54,4 @@ void ff_psdsp_init_arm(PSDSPContext *s);
void ff_psdsp_init_mips(PSDSPContext *s);
void ff_psdsp_init_x86(PSDSPContext *s);
#endif /* LIBAVCODEC_AACPSDSP_H */
#endif /* AVCODEC_AACPSDSP_H */

Some files were not shown because too many files have changed in this diff Show More